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
11 #include <math.h>
12
13 #include <vtkm/Math.h>
14 #include <vtkm/VectorAnalysis.h>
15
16 #include <vtkm/cont/Algorithm.h>
17 #include <vtkm/cont/DeviceAdapter.h>
18 #include <vtkm/cont/DeviceAdapterAlgorithm.h>
19 #include <vtkm/cont/Invoker.h>
20 #include <vtkm/cont/RuntimeDeviceTracker.h>
21 #include <vtkm/cont/TryExecute.h>
22
23 #include <vtkm/cont/AtomicArray.h>
24
25 #include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
26 #include <vtkm/rendering/raytracing/Logger.h>
27 #include <vtkm/rendering/raytracing/MortonCodes.h>
28 #include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
29 #include <vtkm/rendering/raytracing/Worklets.h>
30
31 #include <vtkm/worklet/WorkletMapField.h>
32
33 #define AABB_EPSILON 0.00001f
34 namespace vtkm
35 {
36 namespace rendering
37 {
38 namespace raytracing
39 {
40 namespace detail
41 {
42
43 class LinearBVHBuilder
44 {
45 public:
46 class CountingIterator;
47
48 class GatherFloat32;
49
50 template <typename Device>
51 class GatherVecCast;
52
53 class CreateLeafs;
54
55 class BVHData;
56
57 class PropagateAABBs;
58
59 class TreeBuilder;
60
61 VTKM_CONT
LinearBVHBuilder()62 LinearBVHBuilder() {}
63
64 VTKM_CONT void SortAABBS(BVHData& bvh, bool);
65
66 VTKM_CONT void BuildHierarchy(BVHData& bvh);
67
68 VTKM_CONT void Build(LinearBVH& linearBVH);
69 }; // class LinearBVHBuilder
70
71 class LinearBVHBuilder::CountingIterator : public vtkm::worklet::WorkletMapField
72 {
73 public:
74 VTKM_CONT
CountingIterator()75 CountingIterator() {}
76 using ControlSignature = void(FieldOut);
77 using ExecutionSignature = void(WorkIndex, _1);
78 VTKM_EXEC
operator ()(const vtkm::Id & index,vtkm::Id & outId) const79 void operator()(const vtkm::Id& index, vtkm::Id& outId) const { outId = index; }
80 }; //class countingIterator
81
82 class LinearBVHBuilder::GatherFloat32 : public vtkm::worklet::WorkletMapField
83 {
84 public:
85 VTKM_CONT
GatherFloat32()86 GatherFloat32() {}
87 using ControlSignature = void(FieldIn, WholeArrayIn, WholeArrayOut);
88 using ExecutionSignature = void(WorkIndex, _1, _2, _3);
89
90 template <typename InType, typename OutType>
operator ()(const vtkm::Id & outIndex,const vtkm::Id & inIndex,const InType & inPortal,OutType & outPortal) const91 VTKM_EXEC void operator()(const vtkm::Id& outIndex,
92 const vtkm::Id& inIndex,
93 const InType& inPortal,
94 OutType& outPortal) const
95 {
96 outPortal.Set(outIndex, inPortal.Get(inIndex));
97 }
98 }; //class GatherFloat
99
100 class LinearBVHBuilder::CreateLeafs : public vtkm::worklet::WorkletMapField
101 {
102
103 public:
104 VTKM_CONT
CreateLeafs()105 CreateLeafs() {}
106
107 typedef void ControlSignature(FieldIn, WholeArrayOut);
108 typedef void ExecutionSignature(_1, _2, WorkIndex);
109
110 template <typename LeafPortalType>
operator ()(const vtkm::Id & dataIndex,LeafPortalType & leafs,const vtkm::Id & index) const111 VTKM_EXEC void operator()(const vtkm::Id& dataIndex,
112 LeafPortalType& leafs,
113 const vtkm::Id& index) const
114 {
115 const vtkm::Id offset = index * 2;
116 leafs.Set(offset, 1); // number of primitives
117 leafs.Set(offset + 1, dataIndex); // number of primitives
118 }
119 }; //class createLeafs
120
121 template <typename DeviceAdapterTag>
122 class LinearBVHBuilder::GatherVecCast : public vtkm::worklet::WorkletMapField
123 {
124 private:
125 using Vec4IdArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Id4>;
126 using Vec4IntArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec4i_32>;
127 using PortalConst = typename Vec4IdArrayHandle::ReadPortalType;
128 using Portal = typename Vec4IntArrayHandle::WritePortalType;
129
130 private:
131 PortalConst InputPortal;
132 Portal OutputPortal;
133
134 public:
135 VTKM_CONT
GatherVecCast(const Vec4IdArrayHandle & inputPortal,Vec4IntArrayHandle & outputPortal,const vtkm::Id & size)136 GatherVecCast(const Vec4IdArrayHandle& inputPortal,
137 Vec4IntArrayHandle& outputPortal,
138 const vtkm::Id& size)
139 : InputPortal(inputPortal.PrepareForInput(DeviceAdapterTag()))
140 {
141 this->OutputPortal = outputPortal.PrepareForOutput(size, DeviceAdapterTag());
142 }
143 using ControlSignature = void(FieldIn);
144 using ExecutionSignature = void(WorkIndex, _1);
145 VTKM_EXEC
operator ()(const vtkm::Id & outIndex,const vtkm::Id & inIndex) const146 void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
147 {
148 OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
149 }
150 }; //class GatherVec3Id
151
152 class LinearBVHBuilder::BVHData
153 {
154 public:
155 vtkm::cont::ArrayHandle<vtkm::UInt32> mortonCodes;
156 vtkm::cont::ArrayHandle<vtkm::Id> parent;
157 vtkm::cont::ArrayHandle<vtkm::Id> leftChild;
158 vtkm::cont::ArrayHandle<vtkm::Id> rightChild;
159 vtkm::cont::ArrayHandle<vtkm::Id> leafs;
160 vtkm::cont::ArrayHandle<vtkm::Bounds> innerBounds;
161 vtkm::cont::ArrayHandleCounting<vtkm::Id> leafOffsets;
162 AABBs& AABB;
163
BVHData(vtkm::Id numPrimitives,AABBs & aabbs)164 VTKM_CONT BVHData(vtkm::Id numPrimitives, AABBs& aabbs)
165 : leafOffsets(0, 2, numPrimitives)
166 , AABB(aabbs)
167 , NumPrimitives(numPrimitives)
168 {
169 InnerNodeCount = NumPrimitives - 1;
170 vtkm::Id size = NumPrimitives + InnerNodeCount;
171
172 parent.Allocate(size);
173 leftChild.Allocate(InnerNodeCount);
174 rightChild.Allocate(InnerNodeCount);
175 innerBounds.Allocate(InnerNodeCount);
176 mortonCodes.Allocate(NumPrimitives);
177 }
178
179 VTKM_CONT
~BVHData()180 ~BVHData() {}
181
182 VTKM_CONT
GetNumberOfPrimitives() const183 vtkm::Id GetNumberOfPrimitives() const { return NumPrimitives; }
184 VTKM_CONT
GetNumberOfInnerNodes() const185 vtkm::Id GetNumberOfInnerNodes() const { return InnerNodeCount; }
186
187 private:
188 vtkm::Id NumPrimitives;
189 vtkm::Id InnerNodeCount;
190
191 }; // class BVH
192
193 class LinearBVHBuilder::PropagateAABBs : public vtkm::worklet::WorkletMapField
194 {
195 private:
196 vtkm::Int32 LeafCount;
197
198 public:
199 VTKM_CONT
PropagateAABBs(vtkm::Int32 leafCount)200 PropagateAABBs(vtkm::Int32 leafCount)
201 : LeafCount(leafCount)
202
203 {
204 }
205 using ControlSignature = void(WholeArrayIn,
206 WholeArrayIn,
207 WholeArrayIn,
208 WholeArrayIn,
209 WholeArrayIn,
210 WholeArrayIn,
211 WholeArrayIn,
212 WholeArrayIn, //Parents
213 WholeArrayIn, //lchild
214 WholeArrayIn, //rchild
215 AtomicArrayInOut, //counters
216 WholeArrayInOut // flatbvh
217 );
218 using ExecutionSignature = void(WorkIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12);
219
220 template <typename InputPortalType,
221 typename OffsetPortalType,
222 typename IdPortalType,
223 typename AtomicType,
224 typename BVHType>
operator ()(const vtkm::Id workIndex,const InputPortalType & xmin,const InputPortalType & ymin,const InputPortalType & zmin,const InputPortalType & xmax,const InputPortalType & ymax,const InputPortalType & zmax,const OffsetPortalType & leafOffsets,const IdPortalType & parents,const IdPortalType & leftChildren,const IdPortalType & rightChildren,AtomicType & counters,BVHType & flatBVH) const225 VTKM_EXEC_CONT void operator()(const vtkm::Id workIndex,
226 const InputPortalType& xmin,
227 const InputPortalType& ymin,
228 const InputPortalType& zmin,
229 const InputPortalType& xmax,
230 const InputPortalType& ymax,
231 const InputPortalType& zmax,
232 const OffsetPortalType& leafOffsets,
233 const IdPortalType& parents,
234 const IdPortalType& leftChildren,
235 const IdPortalType& rightChildren,
236 AtomicType& counters,
237 BVHType& flatBVH) const
238
239 {
240 //move up into the inner nodes
241 vtkm::Id currentNode = LeafCount - 1 + workIndex;
242 vtkm::Id2 childVector;
243 while (currentNode != 0)
244 {
245 currentNode = parents.Get(currentNode);
246 vtkm::Int32 oldCount = counters.Add(currentNode, 1);
247 if (oldCount == 0)
248 {
249 return;
250 }
251 vtkm::Id currentNodeOffset = currentNode * 4;
252 childVector[0] = leftChildren.Get(currentNode);
253 childVector[1] = rightChildren.Get(currentNode);
254 if (childVector[0] > (LeafCount - 2))
255 {
256 //our left child is a leaf, so just grab the AABB
257 //and set it in the current node
258 childVector[0] = childVector[0] - LeafCount + 1;
259
260 vtkm::Vec4f_32 first4Vec; // = FlatBVH.Get(currentNode); only this one needs effects this
261
262 first4Vec[0] = xmin.Get(childVector[0]);
263 first4Vec[1] = ymin.Get(childVector[0]);
264 first4Vec[2] = zmin.Get(childVector[0]);
265 first4Vec[3] = xmax.Get(childVector[0]);
266 flatBVH.Set(currentNodeOffset, first4Vec);
267
268 vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
269 second4Vec[0] = ymax.Get(childVector[0]);
270 second4Vec[1] = zmax.Get(childVector[0]);
271 flatBVH.Set(currentNodeOffset + 1, second4Vec);
272 // set index to leaf
273 vtkm::Id leafIndex = leafOffsets.Get(childVector[0]);
274 childVector[0] = -(leafIndex + 1);
275 }
276 else
277 {
278 //our left child is an inner node, so gather
279 //both AABBs in the child and join them for
280 //the current node left AABB.
281 vtkm::Id child = childVector[0] * 4;
282
283 vtkm::Vec4f_32 cFirst4Vec = flatBVH.Get(child);
284 vtkm::Vec4f_32 cSecond4Vec = flatBVH.Get(child + 1);
285 vtkm::Vec4f_32 cThird4Vec = flatBVH.Get(child + 2);
286
287 cFirst4Vec[0] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
288 cFirst4Vec[1] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
289 cFirst4Vec[2] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
290 cFirst4Vec[3] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
291 flatBVH.Set(currentNodeOffset, cFirst4Vec);
292
293 vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
294 second4Vec[0] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
295 second4Vec[1] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
296
297 flatBVH.Set(currentNodeOffset + 1, second4Vec);
298 }
299
300 if (childVector[1] > (LeafCount - 2))
301 {
302 //our right child is a leaf, so just grab the AABB
303 //and set it in the current node
304 childVector[1] = childVector[1] - LeafCount + 1;
305
306
307 vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
308
309 second4Vec[2] = xmin.Get(childVector[1]);
310 second4Vec[3] = ymin.Get(childVector[1]);
311 flatBVH.Set(currentNodeOffset + 1, second4Vec);
312
313 vtkm::Vec4f_32 third4Vec;
314 third4Vec[0] = zmin.Get(childVector[1]);
315 third4Vec[1] = xmax.Get(childVector[1]);
316 third4Vec[2] = ymax.Get(childVector[1]);
317 third4Vec[3] = zmax.Get(childVector[1]);
318 flatBVH.Set(currentNodeOffset + 2, third4Vec);
319
320 // set index to leaf
321 vtkm::Id leafIndex = leafOffsets.Get(childVector[1]);
322 childVector[1] = -(leafIndex + 1);
323 }
324 else
325 {
326 //our left child is an inner node, so gather
327 //both AABBs in the child and join them for
328 //the current node left AABB.
329 vtkm::Id child = childVector[1] * 4;
330
331 vtkm::Vec4f_32 cFirst4Vec = flatBVH.Get(child);
332 vtkm::Vec4f_32 cSecond4Vec = flatBVH.Get(child + 1);
333 vtkm::Vec4f_32 cThird4Vec = flatBVH.Get(child + 2);
334
335 vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
336 second4Vec[2] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
337 second4Vec[3] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
338 flatBVH.Set(currentNodeOffset + 1, second4Vec);
339
340 cThird4Vec[0] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
341 cThird4Vec[1] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
342 cThird4Vec[2] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
343 cThird4Vec[3] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
344 flatBVH.Set(currentNodeOffset + 2, cThird4Vec);
345 }
346 vtkm::Vec4f_32 fourth4Vec{ 0.0f };
347 vtkm::Int32 leftChild =
348 static_cast<vtkm::Int32>((childVector[0] >= 0) ? childVector[0] * 4 : childVector[0]);
349 memcpy(&fourth4Vec[0], &leftChild, 4);
350 vtkm::Int32 rightChild =
351 static_cast<vtkm::Int32>((childVector[1] >= 0) ? childVector[1] * 4 : childVector[1]);
352 memcpy(&fourth4Vec[1], &rightChild, 4);
353 flatBVH.Set(currentNodeOffset + 3, fourth4Vec);
354 }
355 }
356 }; //class PropagateAABBs
357
358 class LinearBVHBuilder::TreeBuilder : public vtkm::worklet::WorkletMapField
359 {
360 private:
361 vtkm::Id LeafCount;
362 vtkm::Id InnerCount;
363 //TODO: get intrinsic support
364 VTKM_EXEC
CountLeadingZeros(vtkm::UInt32 & x) const365 inline vtkm::Int32 CountLeadingZeros(vtkm::UInt32& x) const
366 {
367 vtkm::UInt32 y;
368 vtkm::UInt32 n = 32;
369 y = x >> 16;
370 if (y != 0)
371 {
372 n = n - 16;
373 x = y;
374 }
375 y = x >> 8;
376 if (y != 0)
377 {
378 n = n - 8;
379 x = y;
380 }
381 y = x >> 4;
382 if (y != 0)
383 {
384 n = n - 4;
385 x = y;
386 }
387 y = x >> 2;
388 if (y != 0)
389 {
390 n = n - 2;
391 x = y;
392 }
393 y = x >> 1;
394 if (y != 0)
395 return vtkm::Int32(n - 2);
396 return vtkm::Int32(n - x);
397 }
398
399 // returns the count of largest shared prefix between
400 // two morton codes. Ties are broken by the indexes
401 // a and b.
402 //
403 // returns count of the largest binary prefix
404
405 template <typename MortonType>
delta(const vtkm::Int32 & a,const vtkm::Int32 & b,const MortonType & mortonCodePortal) const406 VTKM_EXEC inline vtkm::Int32 delta(const vtkm::Int32& a,
407 const vtkm::Int32& b,
408 const MortonType& mortonCodePortal) const
409 {
410 bool tie = false;
411 bool outOfRange = (b < 0 || b > LeafCount - 1);
412 //still make the call but with a valid adderss
413 vtkm::Int32 bb = (outOfRange) ? 0 : b;
414 vtkm::UInt32 aCode = mortonCodePortal.Get(a);
415 vtkm::UInt32 bCode = mortonCodePortal.Get(bb);
416 //use xor to find where they differ
417 vtkm::UInt32 exOr = aCode ^ bCode;
418 tie = (exOr == 0);
419 //break the tie, a and b must always differ
420 exOr = tie ? vtkm::UInt32(a) ^ vtkm::UInt32(bb) : exOr;
421 vtkm::Int32 count = CountLeadingZeros(exOr);
422 if (tie)
423 count += 32;
424 count = (outOfRange) ? -1 : count;
425 return count;
426 }
427
428 public:
429 VTKM_CONT
TreeBuilder(const vtkm::Id & leafCount)430 TreeBuilder(const vtkm::Id& leafCount)
431 : LeafCount(leafCount)
432 , InnerCount(leafCount - 1)
433 {
434 }
435 using ControlSignature = void(FieldOut, FieldOut, WholeArrayIn, WholeArrayOut);
436 using ExecutionSignature = void(WorkIndex, _1, _2, _3, _4);
437
438 template <typename MortonType, typename ParentType>
operator ()(const vtkm::Id & index,vtkm::Id & leftChild,vtkm::Id & rightChild,const MortonType & mortonCodePortal,ParentType & parentPortal) const439 VTKM_EXEC void operator()(const vtkm::Id& index,
440 vtkm::Id& leftChild,
441 vtkm::Id& rightChild,
442 const MortonType& mortonCodePortal,
443 ParentType& parentPortal) const
444 {
445 vtkm::Int32 idx = vtkm::Int32(index);
446 //determine range direction
447 vtkm::Int32 d =
448 0 > (delta(idx, idx + 1, mortonCodePortal) - delta(idx, idx - 1, mortonCodePortal)) ? -1 : 1;
449
450 //find upper bound for the length of the range
451 vtkm::Int32 minDelta = delta(idx, idx - d, mortonCodePortal);
452 vtkm::Int32 lMax = 2;
453 while (delta(idx, idx + lMax * d, mortonCodePortal) > minDelta)
454 lMax *= 2;
455
456 //binary search to find the lower bound
457 vtkm::Int32 l = 0;
458 for (int t = lMax / 2; t >= 1; t /= 2)
459 {
460 if (delta(idx, idx + (l + t) * d, mortonCodePortal) > minDelta)
461 l += t;
462 }
463
464 vtkm::Int32 j = idx + l * d;
465 vtkm::Int32 deltaNode = delta(idx, j, mortonCodePortal);
466 vtkm::Int32 s = 0;
467 vtkm::Float32 divFactor = 2.f;
468 //find the split position using a binary search
469 for (vtkm::Int32 t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor);;
470 divFactor *= 2, t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor))
471 {
472 if (delta(idx, idx + (s + t) * d, mortonCodePortal) > deltaNode)
473 {
474 s += t;
475 }
476
477 if (t == 1)
478 break;
479 }
480
481 vtkm::Int32 split = idx + s * d + vtkm::Min(d, 0);
482 //assign parent/child pointers
483 if (vtkm::Min(idx, j) == split)
484 {
485 //leaf
486 parentPortal.Set(split + InnerCount, idx);
487 leftChild = split + InnerCount;
488 }
489 else
490 {
491 //inner node
492 parentPortal.Set(split, idx);
493 leftChild = split;
494 }
495
496
497 if (vtkm::Max(idx, j) == split + 1)
498 {
499 //leaf
500 parentPortal.Set(split + InnerCount + 1, idx);
501 rightChild = split + InnerCount + 1;
502 }
503 else
504 {
505 parentPortal.Set(split + 1, idx);
506 rightChild = split + 1;
507 }
508 }
509 }; // class TreeBuilder
510
SortAABBS(BVHData & bvh,bool singleAABB)511 VTKM_CONT void LinearBVHBuilder::SortAABBS(BVHData& bvh, bool singleAABB)
512 {
513 //create array of indexes to be sorted with morton codes
514 vtkm::cont::ArrayHandle<vtkm::Id> iterator;
515 iterator.Allocate(bvh.GetNumberOfPrimitives());
516
517 vtkm::worklet::DispatcherMapField<CountingIterator> iterDispatcher;
518 iterDispatcher.Invoke(iterator);
519
520 //sort the morton codes
521
522 vtkm::cont::Algorithm::SortByKey(bvh.mortonCodes, iterator);
523
524 vtkm::Id arraySize = bvh.GetNumberOfPrimitives();
525 vtkm::cont::ArrayHandle<vtkm::Float32> temp1;
526 vtkm::cont::ArrayHandle<vtkm::Float32> temp2;
527 temp1.Allocate(arraySize);
528
529 vtkm::worklet::DispatcherMapField<GatherFloat32> gatherDispatcher;
530
531 //xmins
532 gatherDispatcher.Invoke(iterator, bvh.AABB.xmins, temp1);
533
534 temp2 = bvh.AABB.xmins;
535 bvh.AABB.xmins = temp1;
536 temp1 = temp2;
537 //ymins
538 gatherDispatcher.Invoke(iterator, bvh.AABB.ymins, temp1);
539
540 temp2 = bvh.AABB.ymins;
541 bvh.AABB.ymins = temp1;
542 temp1 = temp2;
543 //zmins
544 gatherDispatcher.Invoke(iterator, bvh.AABB.zmins, temp1);
545
546 temp2 = bvh.AABB.zmins;
547 bvh.AABB.zmins = temp1;
548 temp1 = temp2;
549 //xmaxs
550 gatherDispatcher.Invoke(iterator, bvh.AABB.xmaxs, temp1);
551
552 temp2 = bvh.AABB.xmaxs;
553 bvh.AABB.xmaxs = temp1;
554 temp1 = temp2;
555 //ymaxs
556 gatherDispatcher.Invoke(iterator, bvh.AABB.ymaxs, temp1);
557
558 temp2 = bvh.AABB.ymaxs;
559 bvh.AABB.ymaxs = temp1;
560 temp1 = temp2;
561 //zmaxs
562 gatherDispatcher.Invoke(iterator, bvh.AABB.zmaxs, temp1);
563
564 temp2 = bvh.AABB.zmaxs;
565 bvh.AABB.zmaxs = temp1;
566 temp1 = temp2;
567
568 // Create the leaf references
569 bvh.leafs.Allocate(arraySize * 2);
570 // we only actually have a single primitive, but the algorithm
571 // requires 2. Make sure they both point to the original
572 // primitive
573 if (singleAABB)
574 {
575 auto iterPortal = iterator.WritePortal();
576 for (int i = 0; i < 2; ++i)
577 {
578 iterPortal.Set(i, 0);
579 }
580 }
581
582 vtkm::worklet::DispatcherMapField<CreateLeafs> leafDispatcher;
583 leafDispatcher.Invoke(iterator, bvh.leafs);
584
585 } // method SortAABB
586
Build(LinearBVH & linearBVH)587 VTKM_CONT void LinearBVHBuilder::Build(LinearBVH& linearBVH)
588 {
589
590 //
591 //
592 // This algorithm needs at least 2 AABBs
593 //
594 bool singleAABB = false;
595 vtkm::Id numberOfAABBs = linearBVH.GetNumberOfAABBs();
596 if (numberOfAABBs == 1)
597 {
598 numberOfAABBs = 2;
599 singleAABB = true;
600 vtkm::Float32 xmin = linearBVH.AABB.xmins.WritePortal().Get(0);
601 vtkm::Float32 ymin = linearBVH.AABB.ymins.WritePortal().Get(0);
602 vtkm::Float32 zmin = linearBVH.AABB.zmins.WritePortal().Get(0);
603 vtkm::Float32 xmax = linearBVH.AABB.xmaxs.WritePortal().Get(0);
604 vtkm::Float32 ymax = linearBVH.AABB.ymaxs.WritePortal().Get(0);
605 vtkm::Float32 zmax = linearBVH.AABB.zmaxs.WritePortal().Get(0);
606
607 linearBVH.AABB.xmins.Allocate(2);
608 linearBVH.AABB.ymins.Allocate(2);
609 linearBVH.AABB.zmins.Allocate(2);
610 linearBVH.AABB.xmaxs.Allocate(2);
611 linearBVH.AABB.ymaxs.Allocate(2);
612 linearBVH.AABB.zmaxs.Allocate(2);
613 for (int i = 0; i < 2; ++i)
614 {
615 linearBVH.AABB.xmins.WritePortal().Set(i, xmin);
616 linearBVH.AABB.ymins.WritePortal().Set(i, ymin);
617 linearBVH.AABB.zmins.WritePortal().Set(i, zmin);
618 linearBVH.AABB.xmaxs.WritePortal().Set(i, xmax);
619 linearBVH.AABB.ymaxs.WritePortal().Set(i, ymax);
620 linearBVH.AABB.zmaxs.WritePortal().Set(i, zmax);
621 }
622 }
623
624
625 const vtkm::Id numBBoxes = numberOfAABBs;
626 BVHData bvh(numBBoxes, linearBVH.GetAABBs());
627
628
629 // Find the extent of all bounding boxes to generate normalization for morton codes
630 vtkm::Vec3f_32 minExtent(vtkm::Infinity32(), vtkm::Infinity32(), vtkm::Infinity32());
631 vtkm::Vec3f_32 maxExtent(
632 vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32());
633 maxExtent[0] = vtkm::cont::Algorithm::Reduce(bvh.AABB.xmaxs, maxExtent[0], MaxValue());
634 maxExtent[1] = vtkm::cont::Algorithm::Reduce(bvh.AABB.ymaxs, maxExtent[1], MaxValue());
635 maxExtent[2] = vtkm::cont::Algorithm::Reduce(bvh.AABB.zmaxs, maxExtent[2], MaxValue());
636 minExtent[0] = vtkm::cont::Algorithm::Reduce(bvh.AABB.xmins, minExtent[0], MinValue());
637 minExtent[1] = vtkm::cont::Algorithm::Reduce(bvh.AABB.ymins, minExtent[1], MinValue());
638 minExtent[2] = vtkm::cont::Algorithm::Reduce(bvh.AABB.zmins, minExtent[2], MinValue());
639
640 linearBVH.TotalBounds.X.Min = minExtent[0];
641 linearBVH.TotalBounds.X.Max = maxExtent[0];
642 linearBVH.TotalBounds.Y.Min = minExtent[1];
643 linearBVH.TotalBounds.Y.Max = maxExtent[1];
644 linearBVH.TotalBounds.Z.Min = minExtent[2];
645 linearBVH.TotalBounds.Z.Max = maxExtent[2];
646
647 vtkm::Vec3f_32 deltaExtent = maxExtent - minExtent;
648 vtkm::Vec3f_32 inverseExtent;
649 for (int i = 0; i < 3; ++i)
650 {
651 inverseExtent[i] = (deltaExtent[i] == 0.f) ? 0 : 1.f / deltaExtent[i];
652 }
653
654 //Generate the morton codes
655 vtkm::worklet::DispatcherMapField<MortonCodeAABB> mortonDispatch(
656 MortonCodeAABB(inverseExtent, minExtent));
657 mortonDispatch.Invoke(bvh.AABB.xmins,
658 bvh.AABB.ymins,
659 bvh.AABB.zmins,
660 bvh.AABB.xmaxs,
661 bvh.AABB.ymaxs,
662 bvh.AABB.zmaxs,
663 bvh.mortonCodes);
664 linearBVH.Allocate(bvh.GetNumberOfPrimitives());
665
666 SortAABBS(bvh, singleAABB);
667
668 vtkm::worklet::DispatcherMapField<TreeBuilder> treeDispatch(
669 TreeBuilder(bvh.GetNumberOfPrimitives()));
670 treeDispatch.Invoke(bvh.leftChild, bvh.rightChild, bvh.mortonCodes, bvh.parent);
671
672 const vtkm::Int32 primitiveCount = vtkm::Int32(bvh.GetNumberOfPrimitives());
673
674 vtkm::cont::ArrayHandle<vtkm::Int32> counters;
675 counters.Allocate(bvh.GetNumberOfPrimitives() - 1);
676
677 vtkm::cont::ArrayHandleConstant<vtkm::Int32> zero(0, bvh.GetNumberOfPrimitives() - 1);
678 vtkm::cont::Algorithm::Copy(zero, counters);
679
680 vtkm::worklet::DispatcherMapField<PropagateAABBs> propDispatch(PropagateAABBs{ primitiveCount });
681
682 propDispatch.Invoke(bvh.AABB.xmins,
683 bvh.AABB.ymins,
684 bvh.AABB.zmins,
685 bvh.AABB.xmaxs,
686 bvh.AABB.ymaxs,
687 bvh.AABB.zmaxs,
688 bvh.leafOffsets,
689 bvh.parent,
690 bvh.leftChild,
691 bvh.rightChild,
692 counters,
693 linearBVH.FlatBVH);
694
695 linearBVH.Leafs = bvh.leafs;
696 }
697 } //namespace detail
698
LinearBVH()699 LinearBVH::LinearBVH()
700 : IsConstructed(false)
701 , CanConstruct(false){};
702
703 VTKM_CONT
LinearBVH(AABBs & aabbs)704 LinearBVH::LinearBVH(AABBs& aabbs)
705 : AABB(aabbs)
706 , IsConstructed(false)
707 , CanConstruct(true)
708 {
709 }
710
711 VTKM_CONT
LinearBVH(const LinearBVH & other)712 LinearBVH::LinearBVH(const LinearBVH& other)
713 : AABB(other.AABB)
714 , FlatBVH(other.FlatBVH)
715 , Leafs(other.Leafs)
716 , LeafCount(other.LeafCount)
717 , IsConstructed(other.IsConstructed)
718 , CanConstruct(other.CanConstruct)
719 {
720 }
721
Allocate(const vtkm::Id & leafCount)722 VTKM_CONT void LinearBVH::Allocate(const vtkm::Id& leafCount)
723 {
724 LeafCount = leafCount;
725 FlatBVH.Allocate((leafCount - 1) * 4);
726 }
727
Construct()728 void LinearBVH::Construct()
729 {
730 if (IsConstructed)
731 return;
732 if (!CanConstruct)
733 throw vtkm::cont::ErrorBadValue(
734 "Linear BVH: coordinates and triangles must be set before calling construct!");
735
736 detail::LinearBVHBuilder builder;
737 builder.Build(*this);
738 }
739
740 VTKM_CONT
SetData(AABBs & aabbs)741 void LinearBVH::SetData(AABBs& aabbs)
742 {
743 AABB = aabbs;
744 IsConstructed = false;
745 CanConstruct = true;
746 }
747
748 // explicitly export
749 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<
750 // vtkm::cont::DeviceAdapterTagSerial>(vtkm::cont::DeviceAdapterTagSerial);
751 //#ifdef VTKM_ENABLE_TBB
752 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagTBB>(
753 // vtkm::cont::DeviceAdapterTagTBB);
754 //#endif
755 //#ifdef VTKM_ENABLE_OPENMP
756 //template VTKM_CONT_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagOpenMP>(
757 // vtkm::cont::DeviceAdapterTagOpenMP);
758 //#endif
759 //#ifdef VTKM_ENABLE_CUDA
760 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagCuda>(
761 // vtkm::cont::DeviceAdapterTagCuda);
762 //#endif
763 //
764 VTKM_CONT
GetIsConstructed() const765 bool LinearBVH::GetIsConstructed() const
766 {
767 return IsConstructed;
768 }
769
GetNumberOfAABBs() const770 vtkm::Id LinearBVH::GetNumberOfAABBs() const
771 {
772 return AABB.xmins.GetNumberOfValues();
773 }
774
GetAABBs()775 AABBs& LinearBVH::GetAABBs()
776 {
777 return AABB;
778 }
779 }
780 }
781 } // namespace vtkm::rendering::raytracing
782