1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_rendering_raytracing_Ray_Operations_h
11 #define vtk_m_rendering_raytracing_Ray_Operations_h
12 
13 #include <vtkm/Matrix.h>
14 #include <vtkm/rendering/Camera.h>
15 #include <vtkm/rendering/CanvasRayTracer.h>
16 #include <vtkm/rendering/raytracing/ChannelBufferOperations.h>
17 #include <vtkm/rendering/raytracing/Ray.h>
18 #include <vtkm/rendering/raytracing/Worklets.h>
19 #include <vtkm/rendering/vtkm_rendering_export.h>
20 
21 namespace vtkm
22 {
23 namespace rendering
24 {
25 namespace raytracing
26 {
27 namespace detail
28 {
29 
30 class RayStatusFilter : public vtkm::worklet::WorkletMapField
31 {
32 public:
33   VTKM_CONT
RayStatusFilter()34   RayStatusFilter() {}
35   using ControlSignature = void(FieldIn, FieldInOut);
36   using ExecutionSignature = void(_1, _2);
37   VTKM_EXEC
operator()38   void operator()(const vtkm::Id& hitIndex, vtkm::UInt8& rayStatus) const
39   {
40     if (hitIndex == -1)
41       rayStatus = RAY_EXITED_DOMAIN;
42     else if (rayStatus != RAY_EXITED_DOMAIN && rayStatus != RAY_TERMINATED)
43       rayStatus = RAY_ACTIVE;
44     //else printf("Bad status state %d \n",(int)rayStatus);
45   }
46 }; //class RayStatusFileter
47 
48 class RayMapCanvas : public vtkm::worklet::WorkletMapField
49 {
50 protected:
51   vtkm::Matrix<vtkm::Float32, 4, 4> InverseProjView;
52   vtkm::Id Width;
53   vtkm::Float32 DoubleInvHeight;
54   vtkm::Float32 DoubleInvWidth;
55   vtkm::Vec3f_32 Origin;
56 
57 public:
58   VTKM_CONT
RayMapCanvas(const vtkm::Matrix<vtkm::Float32,4,4> & inverseProjView,const vtkm::Id width,const vtkm::Id height,const vtkm::Vec3f_32 & origin)59   RayMapCanvas(const vtkm::Matrix<vtkm::Float32, 4, 4>& inverseProjView,
60                const vtkm::Id width,
61                const vtkm::Id height,
62                const vtkm::Vec3f_32& origin)
63     : InverseProjView(inverseProjView)
64     , Width(width)
65     , Origin(origin)
66   {
67     VTKM_ASSERT(width > 0);
68     VTKM_ASSERT(height > 0);
69     DoubleInvHeight = 2.f / static_cast<vtkm::Float32>(height);
70     DoubleInvWidth = 2.f / static_cast<vtkm::Float32>(width);
71   }
72 
73   using ControlSignature = void(FieldIn, FieldInOut, FieldIn, WholeArrayIn);
74   using ExecutionSignature = void(_1, _2, _3, _4);
75 
76   template <typename Precision, typename DepthPortalType>
operator()77   VTKM_EXEC void operator()(const vtkm::Id& pixelId,
78                             Precision& maxDistance,
79                             const Vec<Precision, 3>& origin,
80                             const DepthPortalType& depths) const
81   {
82     vtkm::Vec4f_32 position;
83     position[0] = static_cast<vtkm::Float32>(pixelId % Width);
84     position[1] = static_cast<vtkm::Float32>(pixelId / Width);
85     position[2] = static_cast<vtkm::Float32>(depths.Get(pixelId));
86     position[3] = 1;
87     // transform into normalized device coordinates (-1,1)
88     position[0] = position[0] * DoubleInvWidth - 1.f;
89     position[1] = position[1] * DoubleInvHeight - 1.f;
90     position[2] = 2.f * position[2] - 1.f;
91     // offset so we don't go all the way to the same point
92     position[2] -= 0.00001f;
93     position = vtkm::MatrixMultiply(InverseProjView, position);
94     vtkm::Vec3f_32 p;
95     p[0] = position[0] / position[3];
96     p[1] = position[1] / position[3];
97     p[2] = position[2] / position[3];
98     p = p - origin;
99 
100 
101     maxDistance = vtkm::Magnitude(p);
102   }
103 }; //class RayMapMinDistances
104 
105 } // namespace detail
106 class RayOperations
107 {
108 public:
109   template <typename T>
ResetStatus(Ray<T> & rays,vtkm::UInt8 status)110   static void ResetStatus(Ray<T>& rays, vtkm::UInt8 status)
111   {
112     vtkm::cont::ArrayHandleConstant<vtkm::UInt8> statusHandle(status, rays.NumRays);
113     vtkm::cont::Algorithm::Copy(statusHandle, rays.Status);
114   }
115 
116   //
117   // Some worklets like triangle intersection do not set the
118   // ray status, so this operation sets the status based on
119   // the ray hit index
120   //
121   template <typename Device, typename T>
UpdateRayStatus(Ray<T> & rays,Device)122   static void UpdateRayStatus(Ray<T>& rays, Device)
123   {
124     vtkm::worklet::DispatcherMapField<detail::RayStatusFilter> dispatcher{ (
125       detail::RayStatusFilter{}) };
126     dispatcher.SetDevice(Device());
127     dispatcher.Invoke(rays.HitIdx, rays.Status);
128   }
129 
130   template <typename T>
UpdateRayStatus(Ray<T> & rays)131   static void UpdateRayStatus(Ray<T>& rays)
132   {
133     vtkm::worklet::DispatcherMapField<detail::RayStatusFilter> dispatcher{ (
134       detail::RayStatusFilter{}) };
135     dispatcher.Invoke(rays.HitIdx, rays.Status);
136   }
137 
138   VTKM_RENDERING_EXPORT static void MapCanvasToRays(Ray<vtkm::Float32>& rays,
139                                                     const vtkm::rendering::Camera& camera,
140                                                     const vtkm::rendering::CanvasRayTracer& canvas);
141 
142   template <typename T>
RaysInMesh(Ray<T> & rays)143   static vtkm::Id RaysInMesh(Ray<T>& rays)
144   {
145     vtkm::Vec<UInt8, 2> maskValues;
146     maskValues[0] = RAY_ACTIVE;
147     maskValues[1] = RAY_LOST;
148 
149     vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
150 
151     vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 2>> dispatcher{ (
152       ManyMask<vtkm::UInt8, 2>{ maskValues }) };
153     dispatcher.Invoke(rays.Status, masks);
154     vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
155     const vtkm::Id initVal = 0;
156     vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal);
157 
158     return count;
159   }
160 
161   template <typename T>
GetStatusCount(Ray<T> & rays,vtkm::Id status)162   static vtkm::Id GetStatusCount(Ray<T>& rays, vtkm::Id status)
163   {
164     vtkm::UInt8 statusUInt8;
165     if (status < 0 || status > 255)
166     {
167       throw vtkm::cont::ErrorBadValue("Rays GetStatusCound: invalid status");
168     }
169 
170     statusUInt8 = static_cast<vtkm::UInt8>(status);
171     vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
172 
173     vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>> dispatcher{ (
174       Mask<vtkm::UInt8>{ statusUInt8 }) };
175     dispatcher.Invoke(rays.Status, masks);
176     vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
177     const vtkm::Id initVal = 0;
178     vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal);
179 
180     return count;
181   }
182 
183   template <typename T>
RaysProcessed(Ray<T> & rays)184   static vtkm::Id RaysProcessed(Ray<T>& rays)
185   {
186     vtkm::Vec<UInt8, 3> maskValues;
187     maskValues[0] = RAY_TERMINATED;
188     maskValues[1] = RAY_EXITED_DOMAIN;
189     maskValues[2] = RAY_ABANDONED;
190 
191     vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
192 
193     vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 3>> dispatcher{ (
194       ManyMask<vtkm::UInt8, 3>{ maskValues }) };
195     dispatcher.Invoke(rays.Status, masks);
196     vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
197     const vtkm::Id initVal = 0;
198     vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal);
199 
200     return count;
201   }
202 
203   template <typename T>
CompactActiveRays(Ray<T> & rays)204   static vtkm::cont::ArrayHandle<vtkm::UInt8> CompactActiveRays(Ray<T>& rays)
205   {
206     vtkm::Vec<UInt8, 1> maskValues;
207     maskValues[0] = RAY_ACTIVE;
208     vtkm::UInt8 statusUInt8 = static_cast<vtkm::UInt8>(RAY_ACTIVE);
209     vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
210 
211     vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>> dispatcher{ (
212       Mask<vtkm::UInt8>{ statusUInt8 }) };
213     dispatcher.Invoke(rays.Status, masks);
214 
215     vtkm::cont::ArrayHandle<T> emptyHandle;
216 
217     rays.Normal =
218       vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle);
219     rays.Origin =
220       vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle);
221     rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle);
222 
223     const vtkm::Int32 numFloatArrays = 18;
224     vtkm::cont::ArrayHandle<T>* floatArrayPointers[numFloatArrays];
225     floatArrayPointers[0] = &rays.OriginX;
226     floatArrayPointers[1] = &rays.OriginY;
227     floatArrayPointers[2] = &rays.OriginZ;
228     floatArrayPointers[3] = &rays.DirX;
229     floatArrayPointers[4] = &rays.DirY;
230     floatArrayPointers[5] = &rays.DirZ;
231     floatArrayPointers[6] = &rays.Distance;
232     floatArrayPointers[7] = &rays.MinDistance;
233     floatArrayPointers[8] = &rays.MaxDistance;
234 
235     floatArrayPointers[9] = &rays.Scalar;
236     floatArrayPointers[10] = &rays.IntersectionX;
237     floatArrayPointers[11] = &rays.IntersectionY;
238     floatArrayPointers[12] = &rays.IntersectionZ;
239     floatArrayPointers[13] = &rays.U;
240     floatArrayPointers[14] = &rays.V;
241     floatArrayPointers[15] = &rays.NormalX;
242     floatArrayPointers[16] = &rays.NormalY;
243     floatArrayPointers[17] = &rays.NormalZ;
244 
245     const int breakPoint = rays.IntersectionDataEnabled ? -1 : 9;
246     for (int i = 0; i < numFloatArrays; ++i)
247     {
248       if (i == breakPoint)
249       {
250         break;
251       }
252       vtkm::cont::ArrayHandle<T> compacted;
253       vtkm::cont::Algorithm::CopyIf(*floatArrayPointers[i], masks, compacted);
254       *floatArrayPointers[i] = compacted;
255     }
256 
257     //
258     // restore the composite vectors
259     //
260     rays.Normal =
261       vtkm::cont::make_ArrayHandleCompositeVector(rays.NormalX, rays.NormalY, rays.NormalZ);
262     rays.Origin =
263       vtkm::cont::make_ArrayHandleCompositeVector(rays.OriginX, rays.OriginY, rays.OriginZ);
264     rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(rays.DirX, rays.DirY, rays.DirZ);
265 
266     vtkm::cont::ArrayHandle<vtkm::Id> compactedHits;
267     vtkm::cont::Algorithm::CopyIf(rays.HitIdx, masks, compactedHits);
268     rays.HitIdx = compactedHits;
269 
270     vtkm::cont::ArrayHandle<vtkm::Id> compactedPixels;
271     vtkm::cont::Algorithm::CopyIf(rays.PixelIdx, masks, compactedPixels);
272     rays.PixelIdx = compactedPixels;
273 
274     vtkm::cont::ArrayHandle<vtkm::UInt8> compactedStatus;
275     vtkm::cont::Algorithm::CopyIf(rays.Status, masks, compactedStatus);
276     rays.Status = compactedStatus;
277 
278     rays.NumRays = rays.Status.ReadPortal().GetNumberOfValues();
279 
280     const size_t bufferCount = static_cast<size_t>(rays.Buffers.size());
281     for (size_t i = 0; i < bufferCount; ++i)
282     {
283       ChannelBufferOperations::Compact(rays.Buffers[i], masks, rays.NumRays);
284     }
285     return masks;
286   }
287 
288   template <typename Device, typename T>
Resize(Ray<T> & rays,const vtkm::Int32 newSize,Device)289   static void Resize(Ray<T>& rays, const vtkm::Int32 newSize, Device)
290   {
291     if (newSize == rays.NumRays)
292       return; //nothing to do
293 
294     rays.NumRays = newSize;
295     vtkm::cont::Token token;
296 
297     if (rays.IntersectionDataEnabled)
298     {
299       rays.IntersectionX.PrepareForOutput(rays.NumRays, Device(), token);
300       rays.IntersectionY.PrepareForOutput(rays.NumRays, Device(), token);
301       rays.IntersectionZ.PrepareForOutput(rays.NumRays, Device(), token);
302       rays.U.PrepareForOutput(rays.NumRays, Device(), token);
303       rays.V.PrepareForOutput(rays.NumRays, Device(), token);
304       rays.Scalar.PrepareForOutput(rays.NumRays, Device(), token);
305 
306       rays.NormalX.PrepareForOutput(rays.NumRays, Device(), token);
307       rays.NormalY.PrepareForOutput(rays.NumRays, Device(), token);
308       rays.NormalZ.PrepareForOutput(rays.NumRays, Device(), token);
309     }
310 
311     rays.OriginX.PrepareForOutput(rays.NumRays, Device(), token);
312     rays.OriginY.PrepareForOutput(rays.NumRays, Device(), token);
313     rays.OriginZ.PrepareForOutput(rays.NumRays, Device(), token);
314 
315     rays.DirX.PrepareForOutput(rays.NumRays, Device(), token);
316     rays.DirY.PrepareForOutput(rays.NumRays, Device(), token);
317     rays.DirZ.PrepareForOutput(rays.NumRays, Device(), token);
318 
319     rays.Distance.PrepareForOutput(rays.NumRays, Device(), token);
320     rays.MinDistance.PrepareForOutput(rays.NumRays, Device(), token);
321     rays.MaxDistance.PrepareForOutput(rays.NumRays, Device(), token);
322     rays.Status.PrepareForOutput(rays.NumRays, Device(), token);
323     rays.HitIdx.PrepareForOutput(rays.NumRays, Device(), token);
324     rays.PixelIdx.PrepareForOutput(rays.NumRays, Device(), token);
325 
326     const size_t bufferCount = static_cast<size_t>(rays.Buffers.size());
327     for (size_t i = 0; i < bufferCount; ++i)
328     {
329       rays.Buffers[i].Resize(rays.NumRays, Device());
330     }
331   }
332 
333   template <typename T>
334   static void CopyDistancesToMin(Ray<T> rays, const T offset = 0.f)
335   {
336     vtkm::worklet::DispatcherMapField<CopyAndOffsetMask<T>> dispatcher{ (
337       CopyAndOffsetMask<T>{ offset, RAY_EXITED_MESH }) };
338     dispatcher.Invoke(rays.Distance, rays.MinDistance, rays.Status);
339   }
340 };
341 }
342 }
343 } // namespace vktm::rendering::raytracing
344 #endif
345