1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 // This software is distributed WITHOUT ANY WARRANTY; without even
6 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 // PURPOSE. See the above copyright notice for more information.
8 //
9 // Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 // Copyright 2015 UT-Battelle, LLC.
11 // Copyright 2015 Los Alamos National Security.
12 //
13 // Under the terms of Contract DE-NA0003525 with NTESS,
14 // the U.S. Government retains certain rights in this software.
15 //
16 // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 // Laboratory (LANL), the U.S. Government retains certain rights in
18 // this software.
19 //============================================================================
20 #include <vtkm/cont/DeviceAdapterAlgorithm.h>
21 #include <vtkm/cont/ErrorBadValue.h>
22 #include <vtkm/cont/Timer.h>
23 #include <vtkm/cont/TryExecute.h>
24 #include <vtkm/cont/internal/DeviceAdapterListHelpers.h>
25
26 #include <vtkm/rendering/raytracing/Camera.h>
27 #include <vtkm/rendering/raytracing/CellIntersector.h>
28 #include <vtkm/rendering/raytracing/CellSampler.h>
29 #include <vtkm/rendering/raytracing/CellTables.h>
30 #include <vtkm/rendering/raytracing/MeshConnectivityBase.h>
31 #include <vtkm/rendering/raytracing/Ray.h>
32 #include <vtkm/rendering/raytracing/RayOperations.h>
33 #include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
34 #include <vtkm/rendering/raytracing/Worklets.h>
35
36 #include <vtkm/worklet/DispatcherMapField.h>
37 #include <vtkm/worklet/DispatcherMapTopology.h>
38 #include <vtkm/worklet/WorkletMapField.h>
39 #include <vtkm/worklet/WorkletMapTopology.h>
40
41 namespace vtkm
42 {
43 namespace rendering
44 {
45 namespace raytracing
46 {
47 namespace detail
48 {
49 template <typename FloatType>
50 template <typename Device>
Compact(vtkm::cont::ArrayHandle<FloatType> & compactedDistances,vtkm::cont::ArrayHandle<UInt8> & masks,Device)51 void RayTracking<FloatType>::Compact(vtkm::cont::ArrayHandle<FloatType>& compactedDistances,
52 vtkm::cont::ArrayHandle<UInt8>& masks,
53 Device)
54 {
55 //
56 // These distances are stored in the rays, and it has
57 // already been compacted.
58 //
59 CurrentDistance = compactedDistances;
60
61 vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
62
63 bool distance1IsEnter = EnterDist == &Distance1;
64
65 vtkm::cont::ArrayHandle<FloatType> compactedDistance1;
66 vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(Distance1, masks, compactedDistance1);
67 Distance1 = compactedDistance1;
68
69 vtkm::cont::ArrayHandle<FloatType> compactedDistance2;
70 vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(Distance2, masks, compactedDistance2);
71 Distance2 = compactedDistance2;
72
73 vtkm::cont::ArrayHandle<vtkm::Int32> compactedExitFace;
74 vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(ExitFace, masks, compactedExitFace);
75 ExitFace = compactedExitFace;
76
77 if (distance1IsEnter)
78 {
79 EnterDist = &Distance1;
80 ExitDist = &Distance2;
81 }
82 else
83 {
84 EnterDist = &Distance2;
85 ExitDist = &Distance1;
86 }
87 }
88
89 template <typename FloatType>
90 template <typename Device>
Init(const vtkm::Id size,vtkm::cont::ArrayHandle<FloatType> & distances,Device)91 void RayTracking<FloatType>::Init(const vtkm::Id size,
92 vtkm::cont::ArrayHandle<FloatType>& distances,
93 Device)
94 {
95
96 ExitFace.PrepareForOutput(size, Device());
97 Distance1.PrepareForOutput(size, Device());
98 Distance2.PrepareForOutput(size, Device());
99
100 CurrentDistance = distances;
101 //
102 // Set the initial Distances
103 //
104 vtkm::worklet::DispatcherMapField<CopyAndOffset<FloatType>> resetDistancesDispatcher(
105 CopyAndOffset<FloatType>(0.0f));
106 resetDistancesDispatcher.SetDevice(Device());
107 resetDistancesDispatcher.Invoke(distances, *EnterDist);
108
109 //
110 // Init the exit faces. This value is used to load the next cell
111 // base on the cell and face it left
112 //
113 vtkm::cont::ArrayHandleConstant<vtkm::Int32> negOne(-1, size);
114 vtkm::cont::Algorithm::Copy(Device(), negOne, ExitFace);
115
116 vtkm::cont::ArrayHandleConstant<FloatType> negOnef(-1.f, size);
117 vtkm::cont::Algorithm::Copy(Device(), negOnef, *ExitDist);
118 }
119
120 template <typename FloatType>
Swap()121 void RayTracking<FloatType>::Swap()
122 {
123 vtkm::cont::ArrayHandle<FloatType>* tmpPtr;
124 tmpPtr = EnterDist;
125 EnterDist = ExitDist;
126 ExitDist = tmpPtr;
127 }
128 } //namespace detail
129
130 template <typename FloatType, typename Device>
PrintRayStatus(Ray<FloatType> & rays,Device)131 void ConnectivityTracer::PrintRayStatus(Ray<FloatType>& rays, Device)
132 {
133 vtkm::Id raysExited = RayOperations::GetStatusCount(rays, RAY_EXITED_MESH, Device());
134 vtkm::Id raysActive = RayOperations::GetStatusCount(rays, RAY_ACTIVE, Device());
135 vtkm::Id raysAbandoned = RayOperations::GetStatusCount(rays, RAY_ABANDONED, Device());
136 vtkm::Id raysExitedDom = RayOperations::GetStatusCount(rays, RAY_EXITED_DOMAIN, Device());
137 std::cout << "\r Ray Status " << std::setw(10) << std::left << " Lost " << std::setw(10)
138 << std::left << RaysLost << std::setw(10) << std::left << " Exited " << std::setw(10)
139 << std::left << raysExited << std::setw(10) << std::left << " Active " << std::setw(10)
140 << raysActive << std::setw(10) << std::left << " Abandoned " << std::setw(10)
141 << raysAbandoned << " Exited Domain " << std::setw(10) << std::left << raysExitedDom
142 << "\n";
143 }
144
145 //
146 // Advance Ray
147 // After a ray leaves the mesh, we need to check to see
148 // of the ray re-enters the mesh within this domain. This
149 // function moves the ray forward some offset to prevent
150 // "shadowing" and hitting the same exit point.
151 //
152 template <typename FloatType>
153 class AdvanceRay : public vtkm::worklet::WorkletMapField
154 {
155 FloatType Offset;
156
157 public:
158 VTKM_CONT
AdvanceRay(const FloatType offset=0.00001)159 AdvanceRay(const FloatType offset = 0.00001)
160 : Offset(offset)
161 {
162 }
163 using ControlSignature = void(FieldIn<>, FieldInOut<>);
164 using ExecutionSignature = void(_1, _2);
165
operator ()(const vtkm::UInt8 & status,FloatType & distance) const166 VTKM_EXEC inline void operator()(const vtkm::UInt8& status, FloatType& distance) const
167 {
168 if (status == RAY_EXITED_MESH)
169 distance += Offset;
170 }
171 }; //class AdvanceRay
172
173 template <typename FloatType>
174 class LocateCell : public vtkm::worklet::WorkletMapField
175 {
176 private:
177 const MeshConnectivityBase* MeshConn;
178 CellIntersector<255> Intersector;
179
180 public:
LocateCell(const MeshConnectivityBase * meshConn)181 LocateCell(const MeshConnectivityBase* meshConn)
182 : MeshConn(meshConn)
183 {
184 }
185
186 using ControlSignature = void(FieldInOut<>,
187 WholeArrayIn<>,
188 FieldIn<>,
189 FieldInOut<>,
190 FieldInOut<>,
191 FieldInOut<>,
192 FieldInOut<>,
193 FieldIn<>);
194 using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8);
195
196 template <typename PointPortalType>
operator ()(vtkm::Id & currentCell,PointPortalType & vertices,const vtkm::Vec<FloatType,3> & dir,FloatType & enterDistance,FloatType & exitDistance,vtkm::Int32 & enterFace,vtkm::UInt8 & rayStatus,const vtkm::Vec<FloatType,3> & origin) const197 VTKM_EXEC inline void operator()(vtkm::Id& currentCell,
198 PointPortalType& vertices,
199 const vtkm::Vec<FloatType, 3>& dir,
200 FloatType& enterDistance,
201 FloatType& exitDistance,
202 vtkm::Int32& enterFace,
203 vtkm::UInt8& rayStatus,
204 const vtkm::Vec<FloatType, 3>& origin) const
205 {
206 if (enterFace != -1 && rayStatus == RAY_ACTIVE)
207 {
208 currentCell = MeshConn->GetConnectingCell(currentCell, enterFace);
209 if (currentCell == -1)
210 rayStatus = RAY_EXITED_MESH;
211 enterFace = -1;
212 }
213 //This ray is dead or exited the mesh and needs re-entry
214 if (rayStatus != RAY_ACTIVE)
215 {
216 return;
217 }
218 FloatType xpoints[8];
219 FloatType ypoints[8];
220 FloatType zpoints[8];
221 vtkm::Id cellConn[8];
222 FloatType distances[6];
223
224 const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
225 //load local cell data
226 for (int i = 0; i < numIndices; ++i)
227 {
228 BOUNDS_CHECK(vertices, cellConn[i]);
229 vtkm::Vec<FloatType, 3> point = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
230 xpoints[i] = point[0];
231 ypoints[i] = point[1];
232 zpoints[i] = point[2];
233 }
234 const vtkm::UInt8 cellShape = MeshConn->GetCellShape(currentCell);
235 Intersector.IntersectCell(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
236
237 CellTables tables;
238 const vtkm::Int32 numFaces = tables.FaceLookUp(tables.CellTypeLookUp(cellShape), 1);
239 //vtkm::Int32 minFace = 6;
240 vtkm::Int32 maxFace = -1;
241
242 FloatType minDistance = static_cast<FloatType>(1e32);
243 FloatType maxDistance = static_cast<FloatType>(-1);
244 int hitCount = 0;
245 for (vtkm::Int32 i = 0; i < numFaces; ++i)
246 {
247 FloatType dist = distances[i];
248
249 if (dist != -1)
250 {
251 hitCount++;
252 if (dist < minDistance)
253 {
254 minDistance = dist;
255 //minFace = i;
256 }
257 if (dist > maxDistance)
258 {
259 maxDistance = dist;
260 maxFace = i;
261 }
262 }
263 }
264
265 if (maxDistance <= enterDistance || minDistance == maxDistance)
266 {
267 rayStatus = RAY_LOST;
268 }
269 else
270 {
271 enterDistance = minDistance;
272 exitDistance = maxDistance;
273 enterFace = maxFace;
274 }
275
276 } //operator
277 }; //class LocateCell
278
279 template <typename FloatType, typename Device>
280 class RayBumper : public vtkm::worklet::WorkletMapField
281 {
282 private:
283 using FloatTypeHandle = typename vtkm::cont::ArrayHandle<FloatType>;
284 using FloatTypePortal = typename FloatTypeHandle::template ExecutionTypes<Device>::Portal;
285 FloatTypePortal DirectionsX;
286 FloatTypePortal DirectionsY;
287 FloatTypePortal DirectionsZ;
288 const MeshConnectivityBase* MeshConn;
289 CellIntersector<255> Intersector;
290 const vtkm::UInt8 FailureStatus; // the status to assign ray if we fail to find the intersection
291 public:
RayBumper(FloatTypeHandle dirsx,FloatTypeHandle dirsy,FloatTypeHandle dirsz,const MeshConnectivityBase * meshConn,vtkm::UInt8 failureStatus=RAY_ABANDONED)292 RayBumper(FloatTypeHandle dirsx,
293 FloatTypeHandle dirsy,
294 FloatTypeHandle dirsz,
295 const MeshConnectivityBase* meshConn,
296 vtkm::UInt8 failureStatus = RAY_ABANDONED)
297 : DirectionsX(dirsx.PrepareForInPlace(Device()))
298 , DirectionsY(dirsy.PrepareForInPlace(Device()))
299 , DirectionsZ(dirsz.PrepareForInPlace(Device()))
300 , MeshConn(meshConn)
301 , FailureStatus(failureStatus)
302 {
303 }
304
305
306 using ControlSignature = void(FieldInOut<>,
307 WholeArrayIn<>,
308 FieldInOut<>,
309 FieldInOut<>,
310 FieldInOut<>,
311 FieldInOut<>,
312 FieldIn<>);
313 using ExecutionSignature = void(_1, _2, _3, _4, _5, WorkIndex, _6, _7);
314
315 template <typename PointPortalType>
operator ()(vtkm::Id & currentCell,PointPortalType & vertices,FloatType & enterDistance,FloatType & exitDistance,vtkm::Int32 & enterFace,const vtkm::Id & pixelIndex,vtkm::UInt8 & rayStatus,const vtkm::Vec<FloatType,3> & origin) const316 VTKM_EXEC inline void operator()(vtkm::Id& currentCell,
317 PointPortalType& vertices,
318 FloatType& enterDistance,
319 FloatType& exitDistance,
320 vtkm::Int32& enterFace,
321 const vtkm::Id& pixelIndex,
322 vtkm::UInt8& rayStatus,
323 const vtkm::Vec<FloatType, 3>& origin) const
324 {
325 // We only process lost rays
326 if (rayStatus != RAY_LOST)
327 {
328 return;
329 }
330
331 FloatType xpoints[8];
332 FloatType ypoints[8];
333 FloatType zpoints[8];
334 vtkm::Id cellConn[8];
335 FloatType distances[6];
336
337 vtkm::Vec<FloatType, 3> centroid(0., 0., 0.);
338
339 const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
340 //load local cell data
341 for (int i = 0; i < numIndices; ++i)
342 {
343 BOUNDS_CHECK(vertices, cellConn[i]);
344 vtkm::Vec<FloatType, 3> point = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
345 centroid = centroid + point;
346 xpoints[i] = point[0];
347 ypoints[i] = point[1];
348 zpoints[i] = point[2];
349 }
350
351 FloatType invNumIndices = static_cast<FloatType>(1.) / static_cast<FloatType>(numIndices);
352 centroid[0] = centroid[0] * invNumIndices;
353 centroid[1] = centroid[1] * invNumIndices;
354 centroid[2] = centroid[2] * invNumIndices;
355
356 vtkm::Vec<FloatType, 3> toCentroid = centroid - origin;
357 vtkm::Normalize(toCentroid);
358
359 vtkm::Vec<FloatType, 3> dir(
360 DirectionsX.Get(pixelIndex), DirectionsY.Get(pixelIndex), DirectionsZ.Get(pixelIndex));
361 vtkm::Vec<FloatType, 3> bump = toCentroid - dir;
362 dir = dir + RAY_TUG_EPSILON * bump;
363
364 vtkm::Normalize(dir);
365
366 DirectionsX.Set(pixelIndex, dir[0]);
367 DirectionsY.Set(pixelIndex, dir[1]);
368 DirectionsZ.Set(pixelIndex, dir[2]);
369
370 const vtkm::UInt8 cellShape = MeshConn->GetCellShape(currentCell);
371 Intersector.IntersectCell(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
372
373 CellTables tables;
374 const vtkm::Int32 numFaces = tables.FaceLookUp(tables.CellTypeLookUp(cellShape), 1);
375
376 //vtkm::Int32 minFace = 6;
377 vtkm::Int32 maxFace = -1;
378 FloatType minDistance = static_cast<FloatType>(1e32);
379 FloatType maxDistance = static_cast<FloatType>(-1);
380 int hitCount = 0;
381 for (int i = 0; i < numFaces; ++i)
382 {
383 FloatType dist = distances[i];
384
385 if (dist != -1)
386 {
387 hitCount++;
388 if (dist < minDistance)
389 {
390 minDistance = dist;
391 //minFace = i;
392 }
393 if (dist >= maxDistance)
394 {
395 maxDistance = dist;
396 maxFace = i;
397 }
398 }
399 }
400 if (minDistance >= maxDistance)
401 {
402 rayStatus = FailureStatus;
403 }
404 else
405 {
406 enterDistance = minDistance;
407 exitDistance = maxDistance;
408 enterFace = maxFace;
409 rayStatus = RAY_ACTIVE; //re-activate ray
410 }
411
412 } //operator
413 }; //class RayBumper
414
415 template <typename FloatType>
416 class AddPathLengths : public vtkm::worklet::WorkletMapField
417 {
418 public:
419 VTKM_CONT
AddPathLengths()420 AddPathLengths() {}
421
422 using ControlSignature = void(FieldIn<RayStatusType>, // ray status
423 FieldIn<ScalarRenderingTypes>, // cell enter distance
424 FieldIn<ScalarRenderingTypes>, // cell exit distance
425 FieldInOut<ScalarRenderingTypes>); // ray absorption data
426
427 using ExecutionSignature = void(_1, _2, _3, _4);
428
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & distance) const429 VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
430 const FloatType& enterDistance,
431 const FloatType& exitDistance,
432 FloatType& distance) const
433 {
434 if (rayStatus != RAY_ACTIVE)
435 {
436 return;
437 }
438
439 if (exitDistance <= enterDistance)
440 {
441 return;
442 }
443
444 FloatType segmentLength = exitDistance - enterDistance;
445 distance += segmentLength;
446 }
447 };
448
449 template <typename FloatType>
450 class Integrate : public vtkm::worklet::WorkletMapField
451 {
452 private:
453 const vtkm::Int32 NumBins;
454
455 public:
456 VTKM_CONT
Integrate(const vtkm::Int32 numBins)457 Integrate(const vtkm::Int32 numBins)
458 : NumBins(numBins)
459 {
460 }
461
462 using ControlSignature = void(FieldIn<RayStatusType>, // ray status
463 FieldIn<ScalarRenderingTypes>, // cell enter distance
464 FieldIn<ScalarRenderingTypes>, // cell exit distance
465 FieldInOut<ScalarRenderingTypes>, // current distance
466 WholeArrayIn<ScalarRenderingTypes>, // cell absorption data array
467 WholeArrayInOut<ScalarRenderingTypes>, // ray absorption data
468 FieldIn<IdType>); // current cell
469
470 using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, WorkIndex);
471
472 template <typename CellDataPortalType, typename RayDataPortalType>
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const CellDataPortalType & cellData,RayDataPortalType & energyBins,const vtkm::Id & currentCell,const vtkm::Id & rayIndex) const473 VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
474 const FloatType& enterDistance,
475 const FloatType& exitDistance,
476 FloatType& currentDistance,
477 const CellDataPortalType& cellData,
478 RayDataPortalType& energyBins,
479 const vtkm::Id& currentCell,
480 const vtkm::Id& rayIndex) const
481 {
482 if (rayStatus != RAY_ACTIVE)
483 {
484 return;
485 }
486 if (exitDistance <= enterDistance)
487 {
488 return;
489 }
490
491 FloatType segmentLength = exitDistance - enterDistance;
492
493 vtkm::Id rayOffset = NumBins * rayIndex;
494 vtkm::Id cellOffset = NumBins * currentCell;
495 for (vtkm::Int32 i = 0; i < NumBins; ++i)
496 {
497 BOUNDS_CHECK(cellData, cellOffset + i);
498 FloatType absorb = static_cast<FloatType>(cellData.Get(cellOffset + i));
499
500 absorb = vtkm::Exp(-absorb * segmentLength);
501 BOUNDS_CHECK(energyBins, rayOffset + i);
502 FloatType intensity = static_cast<FloatType>(energyBins.Get(rayOffset + i));
503 energyBins.Set(rayOffset + i, intensity * absorb);
504 }
505 currentDistance = exitDistance;
506 }
507 };
508
509 template <typename FloatType>
510 class IntegrateEmission : public vtkm::worklet::WorkletMapField
511 {
512 private:
513 const vtkm::Int32 NumBins;
514 bool DivideEmisByAbsorb;
515
516 public:
517 VTKM_CONT
IntegrateEmission(const vtkm::Int32 numBins,const bool divideEmisByAbsorb)518 IntegrateEmission(const vtkm::Int32 numBins, const bool divideEmisByAbsorb)
519 : NumBins(numBins)
520 , DivideEmisByAbsorb(divideEmisByAbsorb)
521 {
522 }
523
524 using ControlSignature = void(FieldIn<>, // ray status
525 FieldIn<>, // cell enter distance
526 FieldIn<>, // cell exit distance
527 FieldInOut<>, // current distance
528 WholeArrayIn<ScalarRenderingTypes>, // cell absorption data array
529 WholeArrayIn<ScalarRenderingTypes>, // cell emission data array
530 WholeArrayInOut<>, // ray absorption data
531 WholeArrayInOut<>, // ray emission data
532 FieldIn<>); // current cell
533
534 using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8, _9, WorkIndex);
535
536 template <typename CellAbsPortalType, typename CellEmisPortalType, typename RayDataPortalType>
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const CellAbsPortalType & absorptionData,const CellEmisPortalType & emissionData,RayDataPortalType & absorptionBins,RayDataPortalType & emissionBins,const vtkm::Id & currentCell,const vtkm::Id & rayIndex) const537 VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
538 const FloatType& enterDistance,
539 const FloatType& exitDistance,
540 FloatType& currentDistance,
541 const CellAbsPortalType& absorptionData,
542 const CellEmisPortalType& emissionData,
543 RayDataPortalType& absorptionBins,
544 RayDataPortalType& emissionBins,
545 const vtkm::Id& currentCell,
546 const vtkm::Id& rayIndex) const
547 {
548 if (rayStatus != RAY_ACTIVE)
549 {
550 return;
551 }
552 if (exitDistance <= enterDistance)
553 {
554 return;
555 }
556
557 FloatType segmentLength = exitDistance - enterDistance;
558
559 vtkm::Id rayOffset = NumBins * rayIndex;
560 vtkm::Id cellOffset = NumBins * currentCell;
561 for (vtkm::Int32 i = 0; i < NumBins; ++i)
562 {
563 BOUNDS_CHECK(absorptionData, cellOffset + i);
564 FloatType absorb = static_cast<FloatType>(absorptionData.Get(cellOffset + i));
565 BOUNDS_CHECK(emissionData, cellOffset + i);
566 FloatType emission = static_cast<FloatType>(emissionData.Get(cellOffset + i));
567
568 if (DivideEmisByAbsorb)
569 {
570 emission /= absorb;
571 }
572
573 FloatType tmp = vtkm::Exp(-absorb * segmentLength);
574 BOUNDS_CHECK(absorptionBins, rayOffset + i);
575
576 //
577 // Traditionally, we would only keep track of a single intensity value per ray
578 // per bin and we would integrate from the beginning to end of the ray. In a
579 // distributed memory setting, we would move cell data around so that the
580 // entire ray could be traced, but in situ, moving that much cell data around
581 // could blow memory. Here we are keeping track of two values. Total absorption
582 // through this contiguous segment of the mesh, and the amount of emitted energy
583 // that makes it out of this mesh segment. If this is really run on a single node,
584 // we can get the final energy value by multiplying the background intensity by
585 // the total absorption of the mesh segment and add in the amount of emitted
586 // energy that escapes.
587 //
588 FloatType absorbIntensity = static_cast<FloatType>(absorptionBins.Get(rayOffset + i));
589 FloatType emissionIntensity = static_cast<FloatType>(emissionBins.Get(rayOffset + i));
590
591 absorptionBins.Set(rayOffset + i, absorbIntensity * tmp);
592
593 emissionIntensity = emissionIntensity * tmp + emission * (1.f - tmp);
594
595 BOUNDS_CHECK(emissionBins, rayOffset + i);
596 emissionBins.Set(rayOffset + i, emissionIntensity);
597 }
598 currentDistance = exitDistance;
599 }
600 };
601 //
602 // IdentifyMissedRay is a debugging routine that detects
603 // rays that fail to have any value because of a external
604 // intersection and cell intersection mismatch
605 //
606 //
607 class IdentifyMissedRay : public vtkm::worklet::WorkletMapField
608 {
609 public:
610 vtkm::Id Width;
611 vtkm::Id Height;
612 vtkm::Vec<vtkm::Float32, 4> BGColor;
IdentifyMissedRay(const vtkm::Id width,const vtkm::Id height,vtkm::Vec<vtkm::Float32,4> bgcolor)613 IdentifyMissedRay(const vtkm::Id width,
614 const vtkm::Id height,
615 vtkm::Vec<vtkm::Float32, 4> bgcolor)
616 : Width(width)
617 , Height(height)
618 , BGColor(bgcolor)
619 {
620 }
621 using ControlSignature = void(FieldIn<>, WholeArrayIn<>);
622 using ExecutionSignature = void(_1, _2);
623
624
IsBGColor(const vtkm::Vec<vtkm::Float32,4> color) const625 VTKM_EXEC inline bool IsBGColor(const vtkm::Vec<vtkm::Float32, 4> color) const
626 {
627 bool isBG = false;
628
629 if (color[0] == BGColor[0] && color[1] == BGColor[1] && color[2] == BGColor[2] &&
630 color[3] == BGColor[3])
631 isBG = true;
632 return isBG;
633 }
634
635 template <typename ColorBufferType>
operator ()(const vtkm::Id & pixelId,ColorBufferType & buffer) const636 VTKM_EXEC inline void operator()(const vtkm::Id& pixelId, ColorBufferType& buffer) const
637 {
638 vtkm::Id x = pixelId % Width;
639 vtkm::Id y = pixelId / Width;
640
641 // Conservative check, we only want to check pixels in the middle
642 if (x <= 0 || y <= 0)
643 return;
644 if (x >= Width - 1 || y >= Height - 1)
645 return;
646 vtkm::Vec<vtkm::Float32, 4> pixel;
647 pixel[0] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 0));
648 pixel[1] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 1));
649 pixel[2] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 2));
650 pixel[3] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 3));
651 if (!IsBGColor(pixel))
652 return;
653 vtkm::Id p0 = (y)*Width + (x + 1);
654 vtkm::Id p1 = (y)*Width + (x - 1);
655 vtkm::Id p2 = (y + 1) * Width + (x);
656 vtkm::Id p3 = (y - 1) * Width + (x);
657 pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 0));
658 pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 1));
659 pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 2));
660 pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 3));
661 if (IsBGColor(pixel))
662 return;
663 pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 0));
664 pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 1));
665 pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 2));
666 pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 3));
667 if (IsBGColor(pixel))
668 return;
669 pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 0));
670 pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 1));
671 pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 2));
672 pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 3));
673 if (IsBGColor(pixel))
674 return;
675 pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 0));
676 pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 1));
677 pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 2));
678 pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 3));
679 if (IsBGColor(pixel))
680 return;
681
682 printf("Possible error ray missed ray %d\n", (int)pixelId);
683 }
684 };
685
686 template <typename FloatType, typename Device>
687 class SampleCellAssocCells : public vtkm::worklet::WorkletMapField
688 {
689 private:
690 using ColorHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
691 using ColorBuffer = typename vtkm::cont::ArrayHandle<FloatType>;
692 using ColorConstPortal = typename ColorHandle::ExecutionTypes<Device>::PortalConst;
693 using ColorPortal = typename ColorBuffer::template ExecutionTypes<Device>::Portal;
694
695 CellSampler<255> Sampler;
696 FloatType SampleDistance;
697 FloatType MinScalar;
698 FloatType InvDeltaScalar;
699 ColorPortal FrameBuffer;
700 ColorConstPortal ColorMap;
701 const MeshConnectivityBase* MeshConn;
702 vtkm::Int32 ColorMapSize;
703
704 public:
SampleCellAssocCells(const FloatType & sampleDistance,const FloatType & minScalar,const FloatType & maxScalar,ColorHandle & colorMap,ColorBuffer & frameBuffer,const MeshConnectivityBase * meshConn)705 SampleCellAssocCells(const FloatType& sampleDistance,
706 const FloatType& minScalar,
707 const FloatType& maxScalar,
708 ColorHandle& colorMap,
709 ColorBuffer& frameBuffer,
710 const MeshConnectivityBase* meshConn)
711 : SampleDistance(sampleDistance)
712 , MinScalar(minScalar)
713 , ColorMap(colorMap.PrepareForInput(Device()))
714 , MeshConn(meshConn)
715 {
716 InvDeltaScalar = (minScalar == maxScalar) ? 1.f : 1.f / (maxScalar - minScalar);
717 ColorMapSize = static_cast<vtkm::Int32>(ColorMap.GetNumberOfValues());
718 this->FrameBuffer = frameBuffer.PrepareForOutput(frameBuffer.GetNumberOfValues(), Device());
719 }
720
721
722 using ControlSignature = void(FieldIn<>,
723 WholeArrayIn<ScalarRenderingTypes>,
724 FieldIn<>,
725 FieldIn<>,
726 FieldInOut<>,
727 FieldInOut<>);
728 using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, WorkIndex);
729
730 template <typename ScalarPortalType>
operator ()(const vtkm::Id & currentCell,ScalarPortalType & scalarPortal,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,vtkm::UInt8 & rayStatus,const vtkm::Id & pixelIndex) const731 VTKM_EXEC inline void operator()(const vtkm::Id& currentCell,
732 ScalarPortalType& scalarPortal,
733 const FloatType& enterDistance,
734 const FloatType& exitDistance,
735 FloatType& currentDistance,
736 vtkm::UInt8& rayStatus,
737 const vtkm::Id& pixelIndex) const
738 {
739
740 if (rayStatus != RAY_ACTIVE)
741 return;
742
743 vtkm::Vec<vtkm::Float32, 4> color;
744 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
745 color[0] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 0));
746 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
747 color[1] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 1));
748 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
749 color[2] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 2));
750 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
751 color[3] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 3));
752
753 vtkm::Float32 scalar;
754 BOUNDS_CHECK(scalarPortal, currentCell);
755 scalar = vtkm::Float32(scalarPortal.Get(currentCell));
756 //
757 // There can be mismatches in the initial enter distance and the current distance
758 // due to lost rays at cell borders. For now,
759 // we will just advance the current position to the enter distance, since otherwise,
760 // the pixel would never be sampled.
761 //
762 if (currentDistance < enterDistance)
763 currentDistance = enterDistance;
764
765 vtkm::Float32 lerpedScalar;
766 lerpedScalar = static_cast<vtkm::Float32>((scalar - MinScalar) * InvDeltaScalar);
767 vtkm::Id colorIndex = vtkm::Id(lerpedScalar * vtkm::Float32(ColorMapSize));
768 if (colorIndex < 0)
769 colorIndex = 0;
770 if (colorIndex >= ColorMapSize)
771 colorIndex = ColorMapSize - 1;
772 BOUNDS_CHECK(ColorMap, colorIndex);
773 vtkm::Vec<vtkm::Float32, 4> sampleColor = ColorMap.Get(colorIndex);
774
775 while (enterDistance <= currentDistance && currentDistance <= exitDistance)
776 {
777 //composite
778 vtkm::Float32 alpha = sampleColor[3] * (1.f - color[3]);
779 color[0] = color[0] + sampleColor[0] * alpha;
780 color[1] = color[1] + sampleColor[1] * alpha;
781 color[2] = color[2] + sampleColor[2] * alpha;
782 color[3] = alpha + color[3];
783
784 if (color[3] > 1.)
785 {
786 rayStatus = RAY_TERMINATED;
787 break;
788 }
789 currentDistance += SampleDistance;
790 }
791
792 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
793 FrameBuffer.Set(pixelIndex * 4 + 0, color[0]);
794 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
795 FrameBuffer.Set(pixelIndex * 4 + 1, color[1]);
796 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
797 FrameBuffer.Set(pixelIndex * 4 + 2, color[2]);
798 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
799 FrameBuffer.Set(pixelIndex * 4 + 3, color[3]);
800 }
801 }; //class Sample cell
802
803 template <typename FloatType, typename Device>
804 class SampleCellAssocPoints : public vtkm::worklet::WorkletMapField
805 {
806 private:
807 using ColorHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
808 using ColorBuffer = typename vtkm::cont::ArrayHandle<FloatType>;
809 using ColorConstPortal = typename ColorHandle::ExecutionTypes<Device>::PortalConst;
810 using ColorPortal = typename ColorBuffer::template ExecutionTypes<Device>::Portal;
811
812 CellSampler<255> Sampler;
813 FloatType SampleDistance;
814 const MeshConnectivityBase* MeshConn;
815 FloatType MinScalar;
816 FloatType InvDeltaScalar;
817 ColorPortal FrameBuffer;
818 ColorConstPortal ColorMap;
819 vtkm::Id ColorMapSize;
820
821 public:
SampleCellAssocPoints(const FloatType & sampleDistance,const FloatType & minScalar,const FloatType & maxScalar,ColorHandle & colorMap,ColorBuffer & frameBuffer,const MeshConnectivityBase * meshConn)822 SampleCellAssocPoints(const FloatType& sampleDistance,
823 const FloatType& minScalar,
824 const FloatType& maxScalar,
825 ColorHandle& colorMap,
826 ColorBuffer& frameBuffer,
827 const MeshConnectivityBase* meshConn)
828 : SampleDistance(sampleDistance)
829 , MeshConn(meshConn)
830 , MinScalar(minScalar)
831 , ColorMap(colorMap.PrepareForInput(Device()))
832 {
833 InvDeltaScalar = (minScalar == maxScalar) ? 1.f : 1.f / (maxScalar - minScalar);
834 ColorMapSize = ColorMap.GetNumberOfValues();
835 this->FrameBuffer = frameBuffer.PrepareForOutput(frameBuffer.GetNumberOfValues(), Device());
836 }
837
838
839 using ControlSignature = void(FieldIn<>,
840 WholeArrayIn<Vec3>,
841 WholeArrayIn<ScalarRenderingTypes>,
842 FieldIn<>,
843 FieldIn<>,
844 FieldInOut<>,
845 FieldIn<>,
846 FieldInOut<>,
847 FieldIn<>);
848 using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8, WorkIndex, _9);
849
850 template <typename PointPortalType, typename ScalarPortalType>
operator ()(const vtkm::Id & currentCell,PointPortalType & vertices,ScalarPortalType & scalarPortal,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const vtkm::Vec<vtkm::Float32,3> & dir,vtkm::UInt8 & rayStatus,const vtkm::Id & pixelIndex,const vtkm::Vec<FloatType,3> & origin) const851 VTKM_EXEC inline void operator()(const vtkm::Id& currentCell,
852 PointPortalType& vertices,
853 ScalarPortalType& scalarPortal,
854 const FloatType& enterDistance,
855 const FloatType& exitDistance,
856 FloatType& currentDistance,
857 const vtkm::Vec<vtkm::Float32, 3>& dir,
858 vtkm::UInt8& rayStatus,
859 const vtkm::Id& pixelIndex,
860 const vtkm::Vec<FloatType, 3>& origin) const
861 {
862
863 if (rayStatus != RAY_ACTIVE)
864 return;
865
866 vtkm::Vec<vtkm::Float32, 4> color;
867 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
868 color[0] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 0));
869 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
870 color[1] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 1));
871 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
872 color[2] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 2));
873 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
874 color[3] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 3));
875
876 if (color[3] >= 1.f)
877 {
878 rayStatus = RAY_TERMINATED;
879 return;
880 }
881 vtkm::Vec<vtkm::Float32, 8> scalars;
882 vtkm::Vec<vtkm::Vec<FloatType, 3>, 8> points;
883 // silence "may" be uninitialized warning
884 for (vtkm::Int32 i = 0; i < 8; ++i)
885 {
886 scalars[i] = 0.f;
887 points[i] = vtkm::Vec<FloatType, 3>(0.f, 0.f, 0.f);
888 }
889 //load local scalar cell data
890 vtkm::Id cellConn[8];
891 const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
892 for (int i = 0; i < numIndices; ++i)
893 {
894 BOUNDS_CHECK(scalarPortal, cellConn[i]);
895 scalars[i] = static_cast<vtkm::Float32>(scalarPortal.Get(cellConn[i]));
896 BOUNDS_CHECK(vertices, cellConn[i]);
897 points[i] = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
898 }
899 //
900 // There can be mismatches in the initial enter distance and the current distance
901 // due to lost rays at cell borders. For now,
902 // we will just advance the current position to the enter distance, since otherwise,
903 // the pixel would never be sampled.
904 //
905 if (currentDistance < enterDistance)
906 {
907 currentDistance = enterDistance;
908 }
909
910 const vtkm::Int32 cellShape = MeshConn->GetCellShape(currentCell);
911 while (enterDistance <= currentDistance && currentDistance <= exitDistance)
912 {
913 vtkm::Vec<FloatType, 3> sampleLoc = origin + currentDistance * dir;
914 vtkm::Float32 lerpedScalar;
915 bool validSample =
916 Sampler.SampleCell(points, scalars, sampleLoc, lerpedScalar, *this, cellShape);
917 if (!validSample)
918 {
919 //
920 // There is a slight mismatch between intersections and parametric coordinates
921 // which results in a invalid sample very close to the cell edge. Just throw
922 // this sample away, and move to the next sample.
923 //
924
925 //There should be a sample here, so offset and try again.
926
927 currentDistance += 0.00001f;
928 continue;
929 }
930 lerpedScalar = static_cast<vtkm::Float32>((lerpedScalar - MinScalar) * InvDeltaScalar);
931 vtkm::Id colorIndex = vtkm::Id(lerpedScalar * vtkm::Float32(ColorMapSize));
932
933 colorIndex = vtkm::Min(vtkm::Max(colorIndex, vtkm::Id(0)), ColorMapSize - 1);
934 BOUNDS_CHECK(ColorMap, colorIndex);
935 vtkm::Vec<vtkm::Float32, 4> sampleColor = ColorMap.Get(colorIndex);
936 //composite
937 sampleColor[3] *= (1.f - color[3]);
938 color[0] = color[0] + sampleColor[0] * sampleColor[3];
939 color[1] = color[1] + sampleColor[1] * sampleColor[3];
940 color[2] = color[2] + sampleColor[2] * sampleColor[3];
941 color[3] = sampleColor[3] + color[3];
942
943 if (color[3] >= 1.0)
944 {
945 rayStatus = RAY_TERMINATED;
946 break;
947 }
948 currentDistance += SampleDistance;
949 }
950
951 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
952 FrameBuffer.Set(pixelIndex * 4 + 0, color[0]);
953 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
954 FrameBuffer.Set(pixelIndex * 4 + 1, color[1]);
955 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
956 FrameBuffer.Set(pixelIndex * 4 + 2, color[2]);
957 BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
958 FrameBuffer.Set(pixelIndex * 4 + 3, color[3]);
959 }
960 }; //class Sample cell
961
962 template <typename FloatType, typename Device>
IntersectCell(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)963 void ConnectivityTracer::IntersectCell(Ray<FloatType>& rays,
964 detail::RayTracking<FloatType>& tracker,
965 const MeshConnectivityBase* meshConn,
966 Device)
967 {
968 using LocateC = LocateCell<FloatType>;
969 vtkm::cont::Timer<Device> timer;
970 vtkm::worklet::DispatcherMapField<LocateC> locateDispatch(meshConn);
971 locateDispatch.SetDevice(Device());
972 locateDispatch.Invoke(rays.HitIdx,
973 this->Coords,
974 rays.Dir,
975 *(tracker.EnterDist),
976 *(tracker.ExitDist),
977 tracker.ExitFace,
978 rays.Status,
979 rays.Origin);
980
981 if (this->CountRayStatus)
982 RaysLost = RayOperations::GetStatusCount(rays, RAY_LOST, Device());
983 this->IntersectTime += timer.GetElapsedTime();
984 }
985
986 template <typename FloatType, typename Device>
AccumulatePathLengths(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,Device)987 void ConnectivityTracer::AccumulatePathLengths(Ray<FloatType>& rays,
988 detail::RayTracking<FloatType>& tracker,
989 Device)
990 {
991 vtkm::worklet::DispatcherMapField<AddPathLengths<FloatType>> dispatcher(
992 (AddPathLengths<FloatType>()));
993 dispatcher.SetDevice(Device());
994 dispatcher.Invoke(
995 rays.Status, *(tracker.EnterDist), *(tracker.ExitDist), rays.GetBuffer("path_lengths").Buffer);
996 }
997
998 template <typename FloatType, typename Device>
FindLostRays(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)999 void ConnectivityTracer::FindLostRays(Ray<FloatType>& rays,
1000 detail::RayTracking<FloatType>& tracker,
1001 const MeshConnectivityBase* meshConn,
1002 Device)
1003 {
1004 using RayB = RayBumper<FloatType, Device>;
1005 vtkm::cont::Timer<Device> timer;
1006
1007 vtkm::worklet::DispatcherMapField<RayB> bumpDispatch(
1008 RayB(rays.DirX, rays.DirY, rays.DirZ, meshConn));
1009 bumpDispatch.SetDevice(Device());
1010 bumpDispatch.Invoke(rays.HitIdx,
1011 this->Coords,
1012 *(tracker.EnterDist),
1013 *(tracker.ExitDist),
1014 tracker.ExitFace,
1015 rays.Status,
1016 rays.Origin);
1017
1018 this->LostRayTime += timer.GetElapsedTime();
1019 }
1020
1021 template <typename FloatType, typename Device>
SampleCells(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)1022 void ConnectivityTracer::SampleCells(Ray<FloatType>& rays,
1023 detail::RayTracking<FloatType>& tracker,
1024 const MeshConnectivityBase* meshConn,
1025 Device)
1026 {
1027 using SampleP = SampleCellAssocPoints<FloatType, Device>;
1028 using SampleC = SampleCellAssocCells<FloatType, Device>;
1029 vtkm::cont::Timer<Device> timer;
1030
1031 VTKM_ASSERT(rays.Buffers.at(0).GetNumChannels() == 4);
1032
1033 if (FieldAssocPoints)
1034 {
1035 vtkm::worklet::DispatcherMapField<SampleP> dispatcher(
1036 SampleP(this->SampleDistance,
1037 vtkm::Float32(this->ScalarBounds.Min),
1038 vtkm::Float32(this->ScalarBounds.Max),
1039 this->ColorMap,
1040 rays.Buffers.at(0).Buffer,
1041 meshConn));
1042 dispatcher.SetDevice(Device());
1043 dispatcher.Invoke(rays.HitIdx,
1044 this->Coords,
1045 this->ScalarField.GetData(),
1046 *(tracker.EnterDist),
1047 *(tracker.ExitDist),
1048 tracker.CurrentDistance,
1049 rays.Dir,
1050 rays.Status,
1051 rays.Origin);
1052 }
1053 else
1054 {
1055 vtkm::worklet::DispatcherMapField<SampleC> dispatcher(
1056 SampleC(this->SampleDistance,
1057 vtkm::Float32(this->ScalarBounds.Min),
1058 vtkm::Float32(this->ScalarBounds.Max),
1059 this->ColorMap,
1060 rays.Buffers.at(0).Buffer,
1061 meshConn));
1062 dispatcher.SetDevice(Device());
1063 dispatcher.Invoke(rays.HitIdx,
1064 this->ScalarField.GetData(),
1065 *(tracker.EnterDist),
1066 *(tracker.ExitDist),
1067 tracker.CurrentDistance,
1068 rays.Status);
1069 }
1070
1071 this->SampleTime += timer.GetElapsedTime();
1072 }
1073
1074 template <typename FloatType, typename Device>
IntegrateCells(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,Device)1075 void ConnectivityTracer::IntegrateCells(Ray<FloatType>& rays,
1076 detail::RayTracking<FloatType>& tracker,
1077 Device)
1078 {
1079 vtkm::cont::Timer<Device> timer;
1080 if (HasEmission)
1081 {
1082 bool divideEmisByAbsorp = false;
1083 vtkm::cont::ArrayHandle<FloatType> absorp = rays.Buffers.at(0).Buffer;
1084 vtkm::cont::ArrayHandle<FloatType> emission = rays.GetBuffer("emission").Buffer;
1085 vtkm::worklet::DispatcherMapField<IntegrateEmission<FloatType>> dispatcher(
1086 IntegrateEmission<FloatType>(rays.Buffers.at(0).GetNumChannels(), divideEmisByAbsorp));
1087 dispatcher.SetDevice(Device());
1088 dispatcher.Invoke(rays.Status,
1089 *(tracker.EnterDist),
1090 *(tracker.ExitDist),
1091 rays.Distance,
1092 this->ScalarField.GetData(),
1093 this->EmissionField.GetData(),
1094 absorp,
1095 emission,
1096 rays.HitIdx);
1097 }
1098 else
1099 {
1100 vtkm::worklet::DispatcherMapField<Integrate<FloatType>> dispatcher(
1101 Integrate<FloatType>(rays.Buffers.at(0).GetNumChannels()));
1102 dispatcher.SetDevice(Device());
1103 dispatcher.Invoke(rays.Status,
1104 *(tracker.EnterDist),
1105 *(tracker.ExitDist),
1106 rays.Distance,
1107 this->ScalarField.GetData(),
1108 rays.Buffers.at(0).Buffer,
1109 rays.HitIdx);
1110 }
1111
1112 IntegrateTime += timer.GetElapsedTime();
1113 }
1114
1115 // template <vtkm::Int32 CellType>
1116 // template <typename FloatType>
1117 // void ConnectivityTracer<CellType>::PrintDebugRay(Ray<FloatType>& rays, vtkm::Id rayId)
1118 // {
1119 // vtkm::Id index = -1;
1120 // for (vtkm::Id i = 0; i < rays.NumRays; ++i)
1121 // {
1122 // if (rays.PixelIdx.GetPortalControl().Get(i) == rayId)
1123 // {
1124 // index = i;
1125 // break;
1126 // }
1127 // }
1128 // if (index == -1)
1129 // {
1130 // return;
1131 // }
1132
1133 // std::cout << "++++++++RAY " << rayId << "++++++++\n";
1134 // std::cout << "Status: " << (int)rays.Status.GetPortalControl().Get(index) << "\n";
1135 // std::cout << "HitIndex: " << rays.HitIdx.GetPortalControl().Get(index) << "\n";
1136 // std::cout << "Dist " << rays.Distance.GetPortalControl().Get(index) << "\n";
1137 // std::cout << "MinDist " << rays.MinDistance.GetPortalControl().Get(index) << "\n";
1138 // std::cout << "Origin " << rays.Origin.GetPortalConstControl().Get(index) << "\n";
1139 // std::cout << "Dir " << rays.Dir.GetPortalConstControl().Get(index) << "\n";
1140 // std::cout << "+++++++++++++++++++++++++\n";
1141 // }
1142
1143 template <typename FloatType, typename Device>
OffsetMinDistances(Ray<FloatType> & rays,Device)1144 void ConnectivityTracer::OffsetMinDistances(Ray<FloatType>& rays, Device)
1145 {
1146 vtkm::worklet::DispatcherMapField<AdvanceRay<FloatType>> dispatcher(
1147 AdvanceRay<FloatType>(FloatType(0.001)));
1148 dispatcher.SetDevice(Device());
1149 dispatcher.Invoke(rays.Status, rays.MinDistance);
1150 }
1151
1152 template <typename Device, typename FloatType>
RenderOnDevice(Ray<FloatType> & rays,Device)1153 void ConnectivityTracer::RenderOnDevice(Ray<FloatType>& rays, Device)
1154 {
1155 this->RaysLost = 0;
1156 Logger* logger = Logger::GetInstance();
1157 logger->OpenLogEntry("conn_tracer");
1158 logger->AddLogData("device", GetDeviceString(Device()));
1159 this->ResetTimers();
1160 vtkm::cont::Timer<Device> renderTimer;
1161
1162 vtkm::cont::DeviceAdapterId devId = Device();
1163
1164 const MeshConnectivityBase* meshConn = MeshContainer->Construct(devId);
1165
1166 bool hasPathLengths = rays.HasBuffer("path_lengths");
1167
1168 vtkm::cont::Timer<Device> timer;
1169 this->Init(); // sets sample distance
1170 //
1171 // All Rays begin as exited to force intersection
1172 //
1173 RayOperations::ResetStatus(rays, RAY_EXITED_MESH, Device());
1174
1175 detail::RayTracking<FloatType> rayTracker;
1176
1177 rayTracker.Init(rays.NumRays, rays.Distance, Device());
1178 vtkm::Float64 time = timer.GetElapsedTime();
1179 logger->AddLogData("init", time);
1180
1181 //CountRayStatus = true;
1182 bool cullMissedRays = true;
1183 bool workRemaining = true;
1184 if (this->CountRayStatus)
1185 {
1186 this->PrintRayStatus(rays, Device());
1187 }
1188
1189 do
1190 {
1191 {
1192 vtkm::cont::Timer<Device> entryTimer;
1193 //
1194 // if ray misses the external face it will be marked RAY_EXITED_MESH
1195 //
1196 MeshContainer->FindEntry(rays, devId);
1197 MeshEntryTime += entryTimer.GetElapsedTime();
1198 }
1199
1200 if (this->CountRayStatus)
1201 {
1202 this->PrintRayStatus(rays, Device());
1203 }
1204 if (cullMissedRays)
1205 {
1206 //TODO: if we always call this after intersection, then
1207 // we could make a specialized version that only compacts
1208 // hitIdx distance and status, resizing everything else.
1209 vtkm::cont::ArrayHandle<UInt8> activeRays;
1210 activeRays = RayOperations::CompactActiveRays(rays, Device());
1211 rayTracker.Compact(rays.Distance, activeRays, Device());
1212 cullMissedRays = false;
1213 }
1214
1215 if (this->CountRayStatus)
1216 {
1217 this->PrintRayStatus(rays, Device());
1218 }
1219 // TODO: we should compact out exited rays once below a threshold
1220 while (RayOperations::RaysInMesh(rays, Device()))
1221 {
1222 //
1223 // Rays the leave the mesh will be marked as RAYEXITED_MESH
1224 this->IntersectCell(rays, rayTracker, meshConn, Device());
1225 //
1226 // If the ray was lost due to precision issues, we find it.
1227 // If it is marked RAY_ABANDONED, then something went wrong.
1228 //
1229 this->FindLostRays(rays, rayTracker, meshConn, Device());
1230 //
1231 // integrate along the ray
1232 //
1233 if (this->Integrator == Volume)
1234 this->SampleCells(rays, rayTracker, meshConn, Device());
1235 else
1236 this->IntegrateCells(rays, rayTracker, Device());
1237
1238 if (hasPathLengths)
1239 {
1240 this->AccumulatePathLengths(rays, rayTracker, Device());
1241 }
1242 //swap enter and exit distances
1243 rayTracker.Swap();
1244 if (this->CountRayStatus)
1245 this->PrintRayStatus(rays, Device());
1246 } //for
1247
1248 workRemaining = RayOperations::RaysProcessed(rays, Device()) != rays.NumRays;
1249 //
1250 // Ensure that we move the current distance forward some
1251 // epsilon so we don't re-enter the cell we just left.
1252 //
1253 if (workRemaining)
1254 {
1255 RayOperations::CopyDistancesToMin(rays, Device());
1256 this->OffsetMinDistances(rays, Device());
1257 }
1258 } while (workRemaining);
1259
1260 if (rays.DebugWidth != -1 && this->Integrator == Volume)
1261 {
1262
1263 vtkm::cont::ArrayHandleCounting<vtkm::Id> pCounter(0, 1, rays.NumRays);
1264 vtkm::worklet::DispatcherMapField<IdentifyMissedRay> dispatcher(
1265 IdentifyMissedRay(rays.DebugWidth, rays.DebugHeight, this->BackgroundColor));
1266 dispatcher.SetDevice(Device());
1267 dispatcher.Invoke(pCounter, rays.Buffers.at(0).Buffer);
1268 }
1269 vtkm::Float64 renderTime = renderTimer.GetElapsedTime();
1270 this->LogTimers();
1271 logger->AddLogData("active_pixels", rays.NumRays);
1272 logger->CloseLogEntry(renderTime);
1273 } //Render
1274 }
1275 }
1276 } // namespace vtkm::rendering::raytracing
1277