HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GEO_BVHImpl.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GEO_BVHImpl.h (GEO Library, C++)
7  *
8  * COMMENTS: Bounding Volume Hierarchy (BVH) implementation for GEO_Detail.
9  */
10 
11 #pragma once
12 
13 #include "GEO_BVH.h"
14 #include <GA/GA_Detail.h>
15 #include <GA/GA_Handle.h>
16 #include <GA/GA_Iterator.h>
17 #include <GA/GA_SplittableRange.h>
18 #include <GA/GA_Types.h>
19 #include <UT/UT_Array.h>
20 #include <UT/UT_BVH.h>
21 #include <UT/UT_BVHImpl.h>
22 #include <UT/UT_ParallelUtil.h>
23 #include <UT/UT_RootFinder.h>
24 #include <UT/UT_SmallArray.h>
25 #include <UT/UT_StopWatch.h>
26 #include <SYS/SYS_Math.h>
27 #include <limits>
28 
29 #define GEO_BVH_INTERLEAVED 1
30 
31 namespace GEO {
32 
33 template<uint NAXES,typename SUBCLASS>
35 {
36  myTree.clear();
37  myNodeBoxes.reset();
38  myPositions.setCapacity(0);
39  myRadii.setCapacity(0);
40  myPosAttrib.clear();
41  myRadAttrib.clear();
42  myPoints.clear();
43  myHasCurvesOrPoints = false;
44 }
45 
46 template<typename VectorType>
47 static bool
48 geoIntersectSphere(
49  VectorType rel_origin, const VectorType &direction,
50  float radius, float &t0, float &t1)
51 {
52  // NOTE: direction should already be normalized!
53 
54  // To stabilize the quadratic equation, we move closer to the centre of the
55  // sphere...
56  float rayt = SYSsqrt(rel_origin.length2()); // SYSsqrt(rel_origin.length2() / direction.length2());
57  VectorType p = rel_origin + rayt*direction;
58 
59  //float a = direction.length2();
60  float b = 2.0F * dot(p, direction);
61  float c = p.length2() - radius*radius;
62 
63  float d = b*b - 4.0F*c; // b*b - 4.0F*a*c
64  if (d < 0)
65  return false;
66 
67  //a = 0.5F/a;
68  d = SYSsqrt(d);
69 
70  t0 = rayt-(b+d); //rayt + a*(-b-d);
71 
72  // TODO: Exclude t1 if rmbackface
73  t1 = rayt-(b-d); //rayt + a*(-b+d);
74 
75  return true;
76 }
77 
78 template<uint NAXES,typename SUBCLASS>
79 template<bool USE_TOLERANCE>
80 struct BVHBase<NAXES,SUBCLASS>::SingleHitFunctor
81 {
83  HitInfo &hit_info) noexcept
84  : myHitInfo(hit_info)
85  , myNestingArrayBase(hit_info.myNestedItemIndices ? hit_info.myNestedItemIndices->size() : 0)
86  {}
87  SYS_FORCE_INLINE void noHit() noexcept
88  {
89  myHitInfo.myItemIndex = -1;
90  myHitInfo.myUVW.assign(0,0,0);
91  myHitInfo.myT = -1.0f;
92  }
94  const UT_Vector3 &hit_uvw,
95  const float t,
96  const uint index,
97  float &limit_t,
98  bool should_clear_nesting = true) noexcept
99  {
100  myHitInfo.myItemIndex = index;
101  myHitInfo.myUVW = hit_uvw;
102  // Clear local portion of nesting array
103  if (should_clear_nesting && myHitInfo.myNestedItemIndices)
104  myHitInfo.myNestedItemIndices->setSize(myNestingArrayBase);
105  myHitInfo.myT = t;
106  limit_t = t;
107  }
109  {
110  hit_info.myNestedItemIndices = myHitInfo.myNestedItemIndices;
111  }
113  {
114  return myHitInfo.myNestedItemIndices;
115  }
117  {
118  return myNestingArrayBase;
119  }
120  SYS_FORCE_INLINE VectorType getNormal(const HitInfo &hit_info) const noexcept
121  { return VectorType(); }
122  SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept {}
123  SYS_FORCE_INLINE void setNormal(HitInfo &hit_info, const VectorType &nml) const noexcept {}
124  SYS_FORCE_INLINE UT_Array<HitInfo> *getHitArray() noexcept { return nullptr; }
125  SYS_FORCE_INLINE exint nestingArrayBase() const noexcept { return myNestingArrayBase; }
126  SYS_FORCE_INLINE UT_Vector3 &lastUVW() noexcept { return myHitInfo.myUVW; }
127 
128  constexpr static bool theAllHits = false;
129  constexpr static bool theNeedsNormal = false;
130  constexpr static bool theUseTolerance = USE_TOLERANCE;
131 
132  using InfoType = HitInfo;
133 
136  float myTolerance;
137 };
138 
139 template<uint NAXES,typename SUBCLASS>
140 template<bool USE_TOLERANCE>
141 struct BVHBase<NAXES,SUBCLASS>::SingleHitAndNormalFunctor
142 {
144  HitInfoAndNormal &hit_info) noexcept
145  : myHitInfo(hit_info)
146  , myNestingArrayBase(hit_info.myNestedItemIndices ? hit_info.myNestedItemIndices->size() : 0)
147  {}
148  SYS_FORCE_INLINE void noHit() noexcept
149  {
150  myHitInfo.myItemIndex = -1;
151  myHitInfo.myUVW.assign(0,0,0);
152  myHitInfo.myT = -1.0f;
153  }
155  const UT_Vector3 &hit_uvw,
156  const float t,
157  const uint index,
158  float &limit_t,
159  bool should_clear_nesting = true) noexcept
160  {
161  myHitInfo.myItemIndex = index;
162  myHitInfo.myUVW = hit_uvw;
163  // Clear local portion of nesting array
164  if (should_clear_nesting && myHitInfo.myNestedItemIndices)
165  myHitInfo.myNestedItemIndices->setSize(myNestingArrayBase);
166  myHitInfo.myT = t;
167  limit_t = t;
168  }
170  {
171  hit_info.myNestedItemIndices = myHitInfo.myNestedItemIndices;
172  }
174  {
175  return myHitInfo.myNestedItemIndices;
176  }
177  SYS_FORCE_INLINE const VectorType &getNormal(const HitInfoAndNormal &hit_info) const noexcept
178  { return hit_info.myNml; }
179  SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
180  {
181  myHitInfo.myNml = nml;
182  }
183  SYS_FORCE_INLINE void setNormal(HitInfoAndNormal &hit_info, const VectorType &nml) const noexcept
184  {
185  hit_info.myNml = nml;
186  }
188  SYS_FORCE_INLINE exint nestingArrayBase() const noexcept { return myNestingArrayBase; }
189  SYS_FORCE_INLINE UT_Vector3 &lastUVW() noexcept { return myHitInfo.myUVW; }
190 
191  constexpr static bool theAllHits = false;
192  constexpr static bool theNeedsNormal = true;
193  constexpr static bool theUseTolerance = USE_TOLERANCE;
194 
196 
199  float myTolerance;
200 };
201 
202 template<uint NAXES,typename SUBCLASS>
203 template<bool USE_TOLERANCE>
204 struct BVHBase<NAXES,SUBCLASS>::AllHitsFunctor
205 {
207  UT_Array<HitInfo> &hit_info,
208  UT_Array<exint> *nesting_temp_array) noexcept
209  : myHitInfo(hit_info)
210  , myNestingTempArray(nesting_temp_array)
211  {}
212  SYS_FORCE_INLINE void noHit() noexcept
213  {
214  // Just don't add a hit.
215  }
217  const UT_Vector3 &hit_uvw,
218  const float t,
219  const uint index,
220  float &limit_t) noexcept
221  {
222  HitInfo hit_info;
223  if (!myNestingTempArray || myNestingTempArray->isEmpty())
224  {
225  // Not nested
226  hit_info.myItemIndex = index;
227  }
228  else
229  {
230  // myItemIndex is the top-most index.
231  hit_info.myItemIndex = (*myNestingTempArray)[0];
232  UT_Array<exint> *new_array = new UT_Array<exint>();
233  hit_info.myNestedItemIndices = new_array;
234  exint n = myNestingTempArray->size();
235  new_array->setSizeNoInit(n);
236  for (exint i = 1; i < n; ++i)
237  {
238  (*new_array)[i-1] = (*myNestingTempArray)[i];
239  }
240  (*new_array)[n-1] = index;
241  }
242  hit_info.myUVW = hit_uvw;
243  hit_info.myT = t;
244  myHitInfo.append(hit_info);
245  }
246  SYS_FORCE_INLINE void setNestingArrayInto(HitInfo &hit_info) noexcept {}
248  {
249  return myNestingTempArray;
250  }
251  SYS_FORCE_INLINE VectorType getNormal(const HitInfo &hit_info) const noexcept
252  { return VectorType(); }
253  SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept {}
254  SYS_FORCE_INLINE void setNormal(HitInfo &hit_info, const VectorType &nml) const noexcept {}
255  SYS_FORCE_INLINE UT_Array<HitInfo> *getHitArray() noexcept { return &myHitInfo; }
256  SYS_FORCE_INLINE exint nestingArrayBase() const noexcept { return 0; }
257  SYS_FORCE_INLINE UT_Vector3 &lastUVW() noexcept { return myHitInfo.last().myUVW; }
258 
259  constexpr static bool theAllHits = true;
260  constexpr static bool theNeedsNormal = false;
261  constexpr static bool theUseTolerance = USE_TOLERANCE;
262 
263  /// NOTE: Intentionally not the array type. See use in GU_BVH::intersectPrim
264  using InfoType = HitInfo;
265 
268  float myTolerance;
269 };
270 
271 template<uint NAXES,typename SUBCLASS>
272 template<bool USE_TOLERANCE>
273 struct BVHBase<NAXES,SUBCLASS>::AllHitsAndNormalsFunctor
274 {
276  UT_Array<HitInfoAndNormal> &hit_info,
277  UT_Array<exint> *nesting_temp_array) noexcept
278  : myHitInfo(hit_info)
279  , myNestingTempArray(nesting_temp_array)
280  {}
281  SYS_FORCE_INLINE void noHit() noexcept
282  {
283  // Just don't add a hit.
284  }
286  const UT_Vector3 &hit_uvw,
287  const float t,
288  const uint index,
289  float &limit_t) noexcept
290  {
291  HitInfoAndNormal hit_info;
292  if (!myNestingTempArray || myNestingTempArray->isEmpty())
293  {
294  // Not nested
295  hit_info.myItemIndex = index;
296  }
297  else
298  {
299  // myItemIndex is the top-most index.
300  hit_info.myItemIndex = (*myNestingTempArray)[0];
301  UT_Array<exint> *new_array = new UT_Array<exint>();
302  hit_info.myNestedItemIndices = new_array;
303  exint n = myNestingTempArray->size();
304  new_array->setSizeNoInit(n);
305  for (exint i = 1; i < n; ++i)
306  {
307  (*new_array)[i-1] = (*myNestingTempArray)[i];
308  }
309  (*new_array)[n-1] = index;
310  }
311  hit_info.myUVW = hit_uvw;
312  hit_info.myT = t;
313  myHitInfo.append(hit_info);
314  }
317  {
318  return myNestingTempArray;
319  }
320  SYS_FORCE_INLINE VectorType getNormal(const HitInfoAndNormal &hit_info) const noexcept
321  { return hit_info.myNml; }
322  SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
323  {
324  myHitInfo.last().myNml = nml;
325  }
326  SYS_FORCE_INLINE void setNormal(HitInfoAndNormal &hit_info, const VectorType &nml) const noexcept
327  {
328  hit_info.myNml = nml;
329  }
330  SYS_FORCE_INLINE UT_Array<HitInfoAndNormal> *getHitArray() noexcept { return &myHitInfo; }
331  SYS_FORCE_INLINE exint nestingArrayBase() const noexcept { return 0; }
332  SYS_FORCE_INLINE UT_Vector3 &lastUVW() noexcept { return myHitInfo.last().myUVW; }
333 
334  constexpr static bool theAllHits = true;
335  constexpr static bool theNeedsNormal = true;
336  constexpr static bool theUseTolerance = USE_TOLERANCE;
337 
338  /// NOTE: Intentionally not the array type. See use in GU_BVH::intersectPrim
340 
343  float myTolerance;
344 };
345 
346 template<uint NAXES,typename SUBCLASS>
347 template<bool farthest,bool rm_backface,bool reverse,typename HitInfoType>
349  const VectorType &origin,
350  const VectorType &direction,
351  HitInfoType &hit_info,
352  float outer_tmin,
353  float outer_tmax) const noexcept
354 {
356  sendRayGeneric<farthest,rm_backface,reverse>(origin, direction, functor, outer_tmin, outer_tmax);
357 }
358 
359 template<uint NAXES,typename SUBCLASS>
360 template<bool farthest,bool rm_backface,bool reverse,typename HitInfoType>
362  const VectorType &origin,
363  const VectorType &direction,
364  HitInfoType &hit_info,
365  float default_radius,
366  float outer_tmin,
367  float outer_tmax) const noexcept
368 {
369  if (!myHasCurvesOrPoints || !myRadii.isEmpty() || default_radius == 0)
370  {
371  // Either there are no points/curves, or we have explicit radii.
372  sendRay<farthest,rm_backface,reverse>(origin, direction, hit_info, outer_tmin, outer_tmax);
373  return;
374  }
376  functor.myTolerance = default_radius;
377  sendRayGeneric<farthest,rm_backface,reverse>(origin, direction, functor, outer_tmin, outer_tmax);
378 }
379 
380 template<uint NAXES,typename SUBCLASS>
381 template<bool rm_backface,bool reverse,bool sort,typename HitInfoType>
383  const VectorType &origin,
384  const VectorType &direction,
385  UT_Array<HitInfoType> &hit_info,
386  UT_Array<exint> *nesting_temp_array,
387  float duplicate_tolerance,
388  float outer_tmin,
389  float outer_tmax) const noexcept
390 {
391  UT_ASSERT_MSG(sort || duplicate_tolerance==0, "Can't remove duplicates if we're not sorting!");
392 
394  sendRayGeneric<false,rm_backface,reverse>(origin, direction, functor, outer_tmin, outer_tmax);
395 
396  if (!sort || hit_info.size() <= 1)
397  return;
398 
399  // Sort by t, breaking ties by index
400  hit_info.sort([](const HitInfo &a, const HitInfo &b) -> bool {
401  if (a.myT < b.myT)
402  return true;
403  if (a.myT > b.myT)
404  return false;
405  // FIXME: Check nesting array, if non-null!!!
406  return (a.myItemIndex < b.myItemIndex);
407  });
408 
409  if (duplicate_tolerance <= 0)
410  return;
411 
412  float prev_t = hit_info[0].myT;
413  exint desti = 1;
414  for (exint i = 1, n = hit_info.size(); i < n; ++i)
415  {
416  float t = hit_info[i].myT;
417  if (t-prev_t < duplicate_tolerance)
418  continue;
419  if (desti != i)
420  hit_info[desti] = hit_info[i];
421  ++desti;
422  }
423  hit_info.setSize(desti);
424 }
425 
426 template<uint NAXES,typename SUBCLASS>
427 template<bool rm_backface,bool reverse,bool sort,typename HitInfoType>
429  const VectorType &origin,
430  const VectorType &direction,
431  UT_Array<HitInfoType> &hit_info,
432  float default_radius,
433  UT_Array<exint> *nesting_temp_array,
434  float duplicate_tolerance,
435  float outer_tmin,
436  float outer_tmax) const noexcept
437 {
438  if (!myHasCurvesOrPoints || !myRadii.isEmpty() || default_radius == 0)
439  {
440  // Either there are no points/curves, or we have explicit radii.
441  sendRayAll<rm_backface,reverse,sort>(origin, direction, hit_info, nesting_temp_array, duplicate_tolerance, outer_tmin, outer_tmax);
442  return;
443  }
444 
445  UT_ASSERT_MSG(sort || duplicate_tolerance==0, "Can't remove duplicates if we're not sorting!");
446 
448  functor.myTolerance = default_radius;
449  sendRayGeneric<false,rm_backface,reverse>(origin, direction, functor, outer_tmin, outer_tmax);
450 
451  if (!sort || hit_info.size() <= 1)
452  return;
453 
454  // Sort by t, breaking ties by index
455  hit_info.sort([](const HitInfo &a, const HitInfo &b) -> bool {
456  if (a.myT < b.myT)
457  return true;
458  if (a.myT > b.myT)
459  return false;
460  // FIXME: Check nesting array, if non-null!!!
461  return (a.myItemIndex < b.myItemIndex);
462  });
463 
464  if (duplicate_tolerance <= 0)
465  return;
466 
467  float prev_t = hit_info[0].myT;
468  exint desti = 1;
469  for (exint i = 1, n = hit_info.size(); i < n; ++i)
470  {
471  float t = hit_info[i].myT;
472  if (t-prev_t < duplicate_tolerance)
473  continue;
474  if (desti != i)
475  hit_info[desti] = hit_info[i];
476  ++desti;
477  }
478  hit_info.setSize(desti);
479 }
480 
481 template<uint NAXES,typename SUBCLASS>
482 template<bool farthest,bool rm_backface,bool reverse,typename FUNCTOR>
483 void BVHBase<NAXES,SUBCLASS>::sendRayGeneric(VectorType origin, VectorType direction, FUNCTOR &hit_info, float outer_tmin, float outer_tmax) const noexcept
484 {
485  using NodeType = typename UT_BVH<BVH_N>::Node;
486  const NodeType *nodes = myTree.getNodes();
487  const uint nnodes = myTree.getNumNodes();
488  float length = direction.normalize();
489 
490  hit_info.noHit();
491  if (nnodes == 0 || length == 0 || !SYSisFinite(length) || !origin.isFinite())
492  {
493  // Nothing to hit
494  return;
495  }
496 
497  const uint num_points = numPoints();
498 
500  for (int i = 0; i < NAXES; ++i)
501  sign[i] = (direction[i] < 0);
502 
503  VectorType inverse_direction;
504  for (int i = 0; i < NAXES; ++i)
505  {
506  // This is deliberately different from SYSsafediv - since for plane
507  // intersection, we need to generate a large result when dividing by 0.
508  inverse_direction[i] = (direction[i] == 0) ? std::numeric_limits<float>::max() : 1/direction[i];
509  }
510 
511  // For intersecting quads, we'll cache a coordinate frame.
512  int max_dir = -1;
513  VectorType N0;
514  VectorType N1;
515 
516  struct StackEntry
517  {
518  uint myNode;
519  float myTMin;
520 
521  SYS_FORCE_INLINE StackEntry() noexcept {}
522  SYS_FORCE_INLINE StackEntry(uint node, float tmin) noexcept
523  : myNode(node)
524  , myTMin(tmin)
525  {}
526  };
527 
528 #if GEO_BVH_INTERLEAVED
530  for (uint axis = 0; axis < NAXES; ++axis)
531  {
532  vorigin[axis] = v4uf(origin[axis]);
533  }
534  UT_FixedVector<v4uf,NAXES> vinverse_direction;
535  for (uint axis = 0; axis < NAXES; ++axis)
536  {
537  vinverse_direction[axis] = v4uf(inverse_direction[axis]);
538  }
539  v4uf vtolerance;
540  if (hit_info.theUseTolerance)
541  vtolerance = v4uf(hit_info.myTolerance);
542 #else
543  const BoxType &box = myNodeBoxes[0];
544  box.intersect(outer_tmin, outer_tmax, sign, origin, inverse_direction);
545 
546  if (outer_tmin > outer_tmax)
547  {
548  // No hits
549  hit_info.noHit();
550  return;
551  }
552 #endif
553 
554  //UT_Vector3 hit_uvw;
555  //exint hit_index = -1;
556 
558 #if GEO_BVH_INTERLEAVED
559  stack.append(StackEntry(NodeType::markInternal(0),(!farthest) ? outer_tmin : outer_tmax));
560 #else
561  stack.append(StackEntry(0,outer_tmin));
562 #endif
563 
564  do
565  {
566  StackEntry entry = stack.last();
567  stack.removeLast();
568 
569  uint next_node = entry.myNode;
570  // When farthest is true, entry.myTMin is actually a tmax.
571  if ((!farthest) ? (entry.myTMin >= outer_tmax) : (entry.myTMin <= outer_tmin))
572  continue;
573 
574  while (true)
575  {
576 #if GEO_BVH_INTERLEAVED
577  if (NodeType::isInternal(next_node))
578  {
579  UT_ASSERT_MSG_P(next_node != NodeType::EMPTY, "How did a ray hit an empty box?");
580 
581  next_node = NodeType::getInternalNum(next_node);
582  const BoxType &box = myNodeBoxes[next_node];
583  v4uf tmin(outer_tmin); v4uf tmax(outer_tmax);
584  if (!hit_info.theUseTolerance)
585  box.intersect(tmin, tmax, sign, vorigin, vinverse_direction);
586  else
587  box.intersectTol(tmin, tmax, sign, vorigin, vinverse_direction, vtolerance);
588 #if 0
589  {
590  uint axis_sign = sign[0];
591  v4uf t1 = (box.vals[0][axis_sign] - vorigin[0]) * vinverse_direction[0];
592  tmin = SYSmax(t1, tmin);
593  v4uf t2 = (box.vals[0][axis_sign^1] - vorigin[0]) * vinverse_direction[0];
594  tmax = SYSmin(t2, tmax);
595  }
596  {
597  uint axis_sign = sign[1];
598  v4uf t1 = (box.vals[1][axis_sign] - vorigin[1]) * vinverse_direction[1];
599  tmin = SYSmax(t1, tmin);
600  v4uf t2 = (box.vals[1][axis_sign^1] - vorigin[1]) * vinverse_direction[1];
601  tmax = SYSmin(t2, tmax);
602  }
603  {
604  uint axis_sign = sign[2];
605  v4uf t1 = (box.vals[2][axis_sign] - vorigin[2]) * vinverse_direction[2];
606  tmin = SYSmax(t1, tmin);
607  v4uf t2 = (box.vals[2][axis_sign^1] - vorigin[2]) * vinverse_direction[2];
608  tmax = SYSmin(t2, tmax);
609  }
610 #endif
611  // NOTE: DO NOT change this to <, else axis-aligned polygons could be missed.
612  v4uu hit_mask = (tmin <= tmax);
613  const uint hit_bits = _mm_movemask_ps(V4SF(hit_mask.vector));
614  if (hit_bits == 0)
615  break;
616  const NodeType &node = nodes[next_node];
617  if (!(hit_bits & (hit_bits-1)))
618  {
619  // Only 1 bit set
620  uint local_index = SYSfirstBitSet(hit_bits);
621 #if 1
622  next_node = node.child[local_index];
623 #else
624  float local_tmin = tmins[local_index];
625  uint child_index = node.child[local_index];
626  if (!stack_size || ((!farthest) ? (stack_last->myTMin >= local_tmin) : (stack_last->myTMin <= local_tmin)))
627  next_node = child_index;
628  else
629  {
630  next_node = stack_last->myNode;
631  stack_last->myNode = child_index;
632  stack_last->myTMin = local_tmin;
633  }
634 #endif
635  continue;
636  }
637 
638  exint stack_size = stack.size();
639  StackEntry *stack_last = stack.data()+stack_size-1;
640 
641  // If we're going to be adding to the stack, we might as
642  // well prune anything from the end of the stack that's
643  // too far, to possibly reduce reallocations.
644  // That said, this probably won't happen often, since
645  // it requires hitting 2 child boxes in the current node
646  // when the next node in the stack must be farther than an
647  // existing hit.
648  // When farthest is true, stack_last->myTMin is actually a tmax.
649  while (stack_size != 0 && ((!farthest) ? (stack_last->myTMin >= outer_tmax) : (stack_last->myTMin <= outer_tmin)))
650  {
651  --stack_size;
652  --stack_last;
653  stack.removeLast();
654  }
655  static constexpr uint two_bit_indices[16][2] = {
656  {4, 4}, {4, 4}, {4, 4}, {0, 1},
657  {4, 4}, {0, 2}, {1, 2}, {0, 1},
658  {4, 4}, {0, 3}, {1, 3}, {0, 1},
659  {2, 3}, {0, 2}, {1, 2}, {0, 1}
660  };
661  static constexpr uint third_bit_index[16] = {
662  4, 4, 4, 4,
663  4, 4, 4, 2,
664  4, 4, 4, 3,
665  4, 3, 3, 2
666  };
667  // When farthest is true, these are tmax's.
668  union { v4sf tminv; float tmins[4]; };
669  tminv = (!farthest) ? tmin.vector : tmax.vector;
670  uint local_index0 = two_bit_indices[hit_bits][0];
671  uint local_index1 = two_bit_indices[hit_bits][1];
672  if (third_bit_index[hit_bits] == 4)
673  {
674  // Only 2 bits set
675  float t0 = tmins[local_index0];
676  float t1 = tmins[local_index1];
677  uint child0 = node.child[local_index0];
678  uint child1 = node.child[local_index1];
679  if ((!farthest) ? (t0 > t1) : (t0 < t1))
680  {
681  uint childtmp = child0;
682  child0 = child1;
683  child1 = childtmp;
684  float tmp = t0;
685  t0 = t1;
686  t1 = tmp;
687  }
688 
689  // When farthest is true, stack_last->myTMin is actually a tmax.
690  if (!stack_size || ((!farthest) ? (stack_last->myTMin >= t0) : (stack_last->myTMin <= t0)))
691  {
692  next_node = child0;
693 
694  // Inserting t1
695  // Check end of stack first, since it's most likely that the box will go near the end.
696  if (!stack_size || ((!farthest) ? (stack_last->myTMin >= t1) : (stack_last->myTMin <= t1)))
697  {
698  stack.append(StackEntry(child1, t1));
699  }
700  else
701  {
702  // Insert in sorted order, but go back at most a constant
703  // number of entries, to avoid n^2 behaviour.
704  exint i;
705  exint limiti = SYSmax(0, stack_size-64);
706  for (i = stack_size-2; i >= limiti; --i)
707  {
708  if ((!farthest) ? (stack[i].myTMin >= t1) : (stack[i].myTMin <= t1))
709  {
710  stack.insert(StackEntry(child1, t1), i+1);
711  break;
712  }
713  }
714  if (i < limiti)
715  {
716  stack.insert(StackEntry(child1, t1), i+1);
717  }
718  }
719  }
720  else
721  {
722  next_node = stack_last->myNode;
723  stack_last->myNode = child1;
724  stack_last->myTMin = t1;
725  stack.append(StackEntry(child0, t0));
726  }
727  continue;
728  }
729 
730  // 3-4 bits set
731  uint nhit = (hit_bits == 0xF) ? 4 : 3;
732  uint local_index2 = third_bit_index[hit_bits];
733  uint children[BVH_N] = {
734  node.child[local_index0],
735  node.child[local_index1],
736  node.child[local_index2],
737  node.child[3]
738  };
739  tmins[0] = tmins[local_index0];
740  tmins[1] = tmins[local_index1];
741  tmins[2] = tmins[local_index2];
742  //tmins[3] = tmins[3];
743 
744  float new_tmin;
745  if (!stack_size || ((!farthest) ? (stack_last->myTMin >= tmins[0]) : (stack_last->myTMin <= tmins[0])))
746  {
747  new_tmin = tmins[0];
748  next_node = children[0];
749  }
750  else
751  {
752  new_tmin = stack_last->myTMin;
753  next_node = stack_last->myNode;
754  stack_last->myTMin = tmins[0];
755  stack_last->myNode = children[0];
756  }
757  for (uint hit = 1; hit < nhit; ++hit)
758  {
759  float t = tmins[hit];
760  uint child = children[hit];
761  if ((!farthest) ? (t < new_tmin) : (t > new_tmin))
762  {
763  float tmpt = new_tmin;
764  uint tmpchild = next_node;
765  new_tmin = t;
766  next_node = child;
767  t = tmpt;
768  child = tmpchild;
769  }
770 
771  // Check end of stack first, since it's most likely that the box will go near the end.
772  if (!stack_size || ((!farthest) ? (stack_last->myTMin >= t) : (stack_last->myTMin <= t)))
773  {
774  stack.append(StackEntry(child, t));
775  }
776  else
777  {
778  // Insert in sorted order, but go back at most a constant
779  // number of entries, to avoid n^2 behaviour.
780  exint i;
781  exint limiti = SYSmax(0, stack_size-64);
782  for (i = stack_size-2; i >= limiti; --i)
783  {
784  if ((!farthest) ? (stack[i].myTMin >= t) : (stack[i].myTMin <= t))
785  {
786  stack.insert(StackEntry(child, t), i+1);
787  break;
788  }
789  }
790  if (i < limiti)
791  {
792  stack.insert(StackEntry(child, t), i+1);
793  }
794  }
795  stack_last = stack.data()+stack_size;
796  ++stack_size;
797  }
798  continue;
799  }
800  uint index = next_node;//myIndices[next_node];
801 #else
802  const NodeType &node = nodes[next_node];
803  uint children[BVH_N];
804  float tmins[BVH_N];
805  uint nnodehits = 0;
806  for (uint i = 0; i < BVH_N; ++i)
807  {
808  const uint itemi = node.child[i];
809  if (NodeType::isInternal(itemi))
810  {
811  if (itemi == NodeType::EMPTY)
812  continue;
813 
814  // Internal node: intersect against box
815  const uint childi = NodeType::getInternalNum(itemi);
816  const BoxType &box = myNodeBoxes[childi];
817  float tmin = outer_tmin; float tmax = outer_tmax;
818  box.intersect(tmin, tmax, sign, origin, inverse_direction);
819  // NOTE: DO NOT change this to >=, else axis-aligned polygons could be missed.
820  if (tmin > tmax)
821  continue;
822 
823  children[nnodehits] = childi;
824  tmins[nnodehits] = tmin;
825  ++nnodehits;
826  }
827  else
828  {
829  // Leaf item: intersect against item
830  uint index = itemi;//myIndices[itemi];
831 #endif
832  if (!SUBCLASS::theHasPrimitives || index < num_points)
833  {
834  // Points as spheres
835  //if (myRadii.isValid())
836  if (!myRadii.isEmpty() || myRadAttrib.isValid() || hit_info.theUseTolerance)
837  {
838  // The point tree subclass reorders myPositions and myRadii
839  // to match the indices in the tree, so we don't need to remap them.
840  exint ptarrayindex = (SUBCLASS::theReordersPositions) ? exint(index) : exint(myPoints(index));
841  const bool use_pos_array = !myPositions.isEmpty();
842  const VectorType pos = use_pos_array ? myPositions[ptarrayindex] : myPosAttrib.get(GA_Offset(ptarrayindex));
843  float radius;
844  if (hit_info.theUseTolerance)
845  radius = hit_info.myTolerance;
846  else if (myRadii.isEmpty())
847  radius = myRadAttrib.get(GA_Offset(ptarrayindex));
848  else
849  radius = ((myRadii.size() == 1) ? myRadii[0] : myRadii[ptarrayindex]);
850  // We already checked for zero radius if theUseTolerance is true
851  if (hit_info.theUseTolerance || radius != 0)
852  {
853  float t0; float t1;
854  const VectorType rel_origin = origin - pos;
855  bool ishit = geoIntersectSphere(rel_origin, direction, radius, t0, t1);
856  if (!ishit)
857 #if GEO_BVH_INTERLEAVED
858  break;
859 #else
860  continue;
861 #endif
862 
863  const float invradius = 1.0f/radius;
864  if ((t0 <= outer_tmax) && (t0 >= outer_tmin))
865  {
866  VectorType p = rel_origin + t0*direction;
867  p *= invradius;
868  // NOTE: p is the normal
869  if (!rm_backface || (dot(p,direction) <= 0) != reverse)
870  {
871  hit_info.insertHit(
872  UT_Vector3(p[0], p[1], (NAXES==3) ? p[2] : 0),
873  t0, index,
874  (!farthest) ? outer_tmax : outer_tmin);
875  if (hit_info.theNeedsNormal)
876  hit_info.setNormal(p);
877  }
878  }
879 
880  if ((t1 <= outer_tmax) && (t1 >= outer_tmin))
881  {
882  VectorType p = rel_origin + t1*direction;
883  p *= invradius;
884  // NOTE: p is the normal
885  if (!rm_backface || (dot(p,direction) <= 0) != reverse)
886  {
887  hit_info.insertHit(
888  UT_Vector3(p[0], p[1], (NAXES==3) ? p[2] : 0),
889  t1, index,
890  (!farthest) ? outer_tmax : outer_tmin);
891  if (hit_info.theNeedsNormal)
892  hit_info.setNormal(p);
893  }
894  }
895  }
896  }
897  }
898  else
899  {
900 #if !GEO_BVH_INTERLEAVED
901  bool ishit =
902 #endif
903  subclass()->template intersectPrim<farthest,rm_backface,reverse>(
904  index, origin, direction, inverse_direction, max_dir, N0, N1,
905  outer_tmax, outer_tmin, hit_info);
906 #if !GEO_BVH_INTERLEAVED
907  if (!ishit)
908  continue;
909 #endif
910  }
911 #if GEO_BVH_INTERLEAVED
912  break;
913 #endif
914 #if !GEO_BVH_INTERLEAVED
915  }
916  }
917  if (nnodehits == 0)
918  break;
919  exint stack_size = stack.size();
920  StackEntry *stack_last = stack.data()+stack_size-1;
921  if (nnodehits == 1)
922  {
923  uint child_index = children[0];
924  if (!stack_size || stack_last->myTMin >= tmins[0])
925  next_node = child_index;
926  else
927  {
928  next_node = stack_last->myNode;
929  stack_last->myNode = child_index;
930  stack_last->myTMin = tmins[0];
931  }
932  }
933  else if (BVH_N == 2 || nnodehits == 2)
934  {
935  const uint local_index = (tmins[0] >= tmins[1]);
936  next_node = children[local_index];
937  const uint insert_node = children[!local_index];
938  const float insert_tmin = tmins[!local_index];
939  // Check end of stack first, since it's most likely that the box will go near the end.
940  if (!stack_size || stack_last->myTMin <= insert_tmin)
941  {
942  stack.append(StackEntry(insert_node, insert_tmin));
943  }
944  else
945  {
946  // Insert in sorted order, but go back at most a constant
947  // number of entries, to avoid n^2 behaviour.
948  exint i;
949  exint limiti = SYSmax(0, stack_size-64);
950  for (i = stack_size-2; i >= limiti; --i)
951  {
952  if (stack[i].myTMin <= insert_tmin)
953  {
954  stack.insert(StackEntry(insert_node, insert_tmin), i+1);
955  break;
956  }
957  }
958  if (i < limiti)
959  {
960  stack.insert(StackEntry(insert_node, insert_tmin), i+1);
961  }
962  }
963  }
964  else
965  {
966  // Sort/insert and keep closest
967  SYS_STATIC_ASSERT_MSG(BVH_N==2, "FIXME: Implement case of BVH_N>2!!!");
968 
969  }
970 #endif
971  }
972  } while (!stack.isEmpty());
973 
974 #if 0
975  if (hit_index >= 0)
976  {
977  hit_info.myItemIndex = hit_index;
978  hit_info.myUVW = hit_uvw;
979  hit_info.myT = (!farthest) ? outer_tmax : outer_tmin;
980  }
981  else
982  {
983  hit_info.myItemIndex = -1;
984  hit_info.myUVW.assign(0,0,0);
985  hit_info.myT = -1.0f;
986  }
987 #endif
988 }
989 
990 template<uint NAXES,typename SUBCLASS>
991 template<bool farthest,typename QUERY_POINT>
993  const QUERY_POINT &query_point,
994  UT::BVHOrderedStack &stack,
995  UT::BVHOrderedStack &output_queue,
996  exint max_points,
997  float max_dist_squared) const noexcept
998 {
999  const v4uu* node_nitems_v = (const v4uu*)myNodeNItems.get();
1000 
1001  const bool use_pos_array = !myPositions.isEmpty();
1002  if (use_pos_array)
1003  {
1004  if (myRadii.size() == 0)
1005  {
1006  if (myRadAttrib.isValid())
1007  {
1008  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1009  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1010  myRadAttrib, max_points, max_dist_squared);
1011  }
1012  else
1013  {
1014  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1015  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1016  UT::ZeroRadiiWrapper{}, max_points, max_dist_squared);
1017  }
1018  }
1019  else if (myRadii.size() == 1)
1020  {
1021  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1022  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1023  UT::SingleRadiusWrapper{myRadii[0]}, max_points, max_dist_squared);
1024  }
1025  else
1026  {
1027  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1028  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1029  myRadii, max_points, max_dist_squared);
1030  }
1031  }
1032  else
1033  {
1034  if (myRadii.size() == 0)
1035  {
1036  if (myRadAttrib.isValid())
1037  {
1038  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1039  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1040  myRadAttrib, max_points, max_dist_squared);
1041  }
1042  else
1043  {
1044  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1045  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1046  UT::ZeroRadiiWrapper{}, max_points, max_dist_squared);
1047  }
1048  }
1049  else if (myRadii.size() == 1)
1050  {
1051  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1052  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1053  UT::SingleRadiusWrapper{myRadii[0]}, max_points, max_dist_squared);
1054  }
1055  else
1056  {
1057  UT::findClosestPoints<farthest,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1058  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1059  myRadii, max_points, max_dist_squared);
1060  }
1061  }
1062 }
1063 
1064 template<uint NAXES,typename SUBCLASS>
1066  VectorType origin, VectorType direction,
1067  const exint max_points, const float max_dist_squared,
1068  UT::BVHOrderedStack& output_queue) const noexcept
1069 {
1070  using PositionArrayType = UT_Array<VectorType>;
1071 
1072  SYS_STATIC_ASSERT(sizeof(myNodeNItems[0]) == sizeof(v4uu) && BVH_N == 4);
1073  UT::BVHOrderedStack stack;
1074  const UT::BVHQueryInfLine<NAXES> query_point{origin, direction};
1075  findMaximalPointsCommon<false>(
1076  query_point,
1077  stack,
1078  output_queue,
1079  max_points,
1080  max_dist_squared);
1081 }
1082 
1083 template<uint NAXES,typename SUBCLASS>
1085  VectorType p0, VectorType p1,
1086  const exint max_points, const float max_dist_squared,
1087  UT::BVHOrderedStack& output_queue) const noexcept
1088 {
1089  using PositionArrayType = UT_Array<VectorType>;
1090 
1091  SYS_STATIC_ASSERT(sizeof(myNodeNItems[0]) == sizeof(v4uu) && BVH_N == 4);
1092  UT::BVHOrderedStack stack;
1093  const UT::BVHQuerySegment<NAXES> query_point{p0, p1};
1094  findMaximalPointsCommon<false>(
1095  query_point,
1096  stack,
1097  output_queue,
1098  max_points,
1099  max_dist_squared);
1100 }
1101 
1102 template<uint NAXES,typename SUBCLASS>
1104  VectorType direction, const float angle, const exint max_points,
1105  const float max_dist_squared, UT::BVHOrderedStack& output_queue) const noexcept
1106 {
1107  using PositionArrayType = UT_Array<VectorType>;
1108 
1109  SYS_STATIC_ASSERT(sizeof(myNodeNItems[0]) == sizeof(v4uu) && BVH_N == 4);
1110  const v4uu* node_nitems_v = (const v4uu*)myNodeNItems.get();
1111  const bool use_pos_array = !myPositions.isEmpty();
1112  UT::BVHOrderedStack stack;
1113  if (myRadii.size() == 0 && !myRadAttrib.isValid())
1114  {
1115  const UT::ZeroRadiiWrapper radii{};
1116  if (use_pos_array)
1117  {
1119  query_point{origin, direction, angle, myPositions, radii};
1120  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1121  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1122  radii, max_points, max_dist_squared);
1123  }
1124  else
1125  {
1127  query_point{origin, direction, angle, myPosAttrib, radii};
1128  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1129  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1130  radii, max_points, max_dist_squared);
1131  }
1132  }
1133  else if (myRadii.size() == 1)
1134  {
1135  const UT::SingleRadiusWrapper radii{myRadii[0]};
1136  if (use_pos_array)
1137  {
1139  query_point{origin, direction, angle, myPositions, radii};
1140  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1141  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1142  radii, max_points, max_dist_squared);
1143  }
1144  else
1145  {
1147  query_point{origin, direction, angle, myPosAttrib, radii};
1148  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1149  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1150  radii, max_points, max_dist_squared);
1151  }
1152  }
1153  else if (myRadii.size() > 1)
1154  {
1155  if (use_pos_array)
1156  {
1158  query_point{origin, direction, angle, myPositions, myRadii};
1159  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1160  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1161  myRadii, max_points, max_dist_squared);
1162  }
1163  else
1164  {
1166  query_point{origin, direction, angle, myPosAttrib, myRadii};
1167  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1168  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1169  myRadii, max_points, max_dist_squared);
1170  }
1171  }
1172  else
1173  {
1174  if (use_pos_array)
1175  {
1177  query_point{origin, direction, angle, myPositions, myRadAttrib};
1178  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1179  myPoints.getArray(), myPositions, query_point, stack, output_queue,
1180  myRadAttrib, max_points, max_dist_squared);
1181  }
1182  else
1183  {
1185  query_point{origin, direction, angle, myPosAttrib, myRadAttrib};
1186  UT::findClosestPoints<false,true,true>(myTree, myNodeBoxes.get(), node_nitems_v,
1187  myPoints.getArray(), myPosAttrib, query_point, stack, output_queue,
1188  myRadAttrib, max_points, max_dist_squared);
1189  }
1190  }
1191 }
1192 
1193 template<uint NAXES,typename SUBCLASS>
1194 template<bool farthest>
1195 void BVHBase<NAXES,SUBCLASS>::findClosest(VectorType origin, MinInfo &hit_info, float max_dist_squared) const noexcept
1196 {
1197  auto default_hit = [&hit_info]()
1198  {
1199  hit_info.myItemIndex = -1;
1200  hit_info.myUVW.assign(0,0,0);
1201  hit_info.myDistSquared = -1.0f;
1202  hit_info.myP = VectorType(typename VectorType::value_type(0));
1203  };
1204 
1205  if (!origin.isFinite())
1206  {
1207  // Nothing to hit
1208  default_hit();
1209  return;
1210  }
1211 
1212  UT_Array<exint> *nesting_array = hit_info.myNestedItemIndices;
1213  exint nesting_array_base = nesting_array ? nesting_array->size() : 0;
1214 
1215 #if GEO_BVH_INTERLEAVED
1217  for (uint axis = 0; axis < NAXES; ++axis)
1218  {
1219  vorigin[axis] = v4uf(origin[axis]);
1220  }
1221 #else
1222  const BoxType &box = myNodeBoxes[0];
1223  float dist2 = (!farthest) ? box.minDistance2(origin) : box.maxDistance2(origin);
1224 
1225  // NOTE: When farthest is true, max_dist_squared is actually a minimum distance squared.
1226  if ((!farthest) ? (dist2 > max_dist_squared) : (dist2 < max_dist_squared))
1227  {
1228  // No hits
1229  hit_info.myItemIndex = -1;
1230  hit_info.myUVW.assign(0,0,0);
1231  hit_info.myDistSquared = -1.0f;
1232  hit_info.myP = VectorType(typename VectorType::value_type(0));
1233  return;
1234  }
1235 #endif
1236 
1237  UT_Vector3 hit_uvw;
1238  exint hit_index = -1;
1239  VectorType hit_position;
1240 
1241  // Record the hit as the closest hit if it
1242  // improves on the given distance criteria.
1243  auto test_hit = [&](auto &max_dist_sq, auto index)
1244  {
1245  if (!SUBCLASS::theHasPrimitives || index < numPoints())
1246  {
1247  // Points as spheres
1248  // The point tree subclass reorders myPositions and myRadii
1249  // to match the indices in the tree, so we don't need to remap them.
1250  exint ptarrayindex = (SUBCLASS::theReordersPositions) ? exint(index)
1251  : exint(myPoints(index));
1252  const bool use_pos_array = !myPositions.isEmpty();
1253  const VectorType pos = use_pos_array ? myPositions[ptarrayindex]
1254  : myPosAttrib.get(GA_Offset(ptarrayindex));
1255 
1256  float radius;
1257  if (myRadii.isEmpty())
1258  radius = myRadAttrib.isValid() ? myRadAttrib.get(GA_Offset(ptarrayindex)) : 0.0f;
1259  else
1260  radius = ((myRadii.size() == 1) ? myRadii[0] : myRadii[ptarrayindex]);
1261  VectorType displacement = origin-pos;
1262  float d2 = displacement.length2();
1263  if (radius == 0)
1264  {
1265  // Zero radius
1266  // When farthest is true, max_dist_sq is actually a minimum distance squared.
1267  if ((!farthest) ? (d2 < max_dist_sq) : (d2 > max_dist_sq))
1268  {
1269  max_dist_sq = d2;
1270  hit_index = index;
1271  hit_uvw.assign(0,0,0);
1272  hit_position = pos;
1273  }
1274  }
1275  else
1276  {
1277  float distance = SYSsqrt(d2) - SYSabs(radius);
1278  d2 = distance*distance;
1279  if ((!farthest) ? (d2 < max_dist_sq) : (d2 > max_dist_sq))
1280  {
1281  max_dist_sq = d2;
1282  hit_index = index;
1283  VectorType normal = displacement;
1284  normal.normalize();
1285  // Real normal is opposite the displacement if radius is negative.
1286  VectorType real_normal = (((radius > 0) != farthest) ? normal : -normal);
1287  hit_uvw[0] = real_normal[0];
1288  hit_uvw[1] = real_normal[1];
1289  hit_uvw[2] = (NAXES==3) ? real_normal[2] : 0;
1290 
1291  // hit_position needs to use normal in the direction of displacement.
1292  hit_position = pos;
1293  if (!farthest)
1294  hit_position -= radius*normal;
1295  else
1296  hit_position += radius*normal;
1297  }
1298  }
1299  }
1300  else
1301  {
1302  subclass()->template closestPrim<farthest>(
1303  index, origin, max_dist_sq,
1304  hit_index, hit_uvw, hit_position,
1305  vorigin, nesting_array, nesting_array_base);
1306  }
1307  };
1308 
1309  if (!traverseBVH<farthest>(vorigin, max_dist_squared, test_hit))
1310  {
1311  default_hit();
1312  return;
1313  }
1314 
1315  if (hit_index >= 0)
1316  {
1317  hit_info.myItemIndex = hit_index;
1318  hit_info.myUVW = hit_uvw;
1319  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1320  hit_info.myDistSquared = max_dist_squared;
1321  hit_info.myP = hit_position;
1322  }
1323  else
1324  default_hit();
1325 
1326 }
1327 
1328 template<uint NAXES,typename SUBCLASS>
1329 template<bool farthest, typename FUNC>
1331  float &max_dist_squared,
1332  FUNC &op) const noexcept
1333 {
1334  using NodeType = typename UT_BVH<BVH_N>::Node;
1335  const NodeType *nodes = myTree.getNodes();
1336  const uint nnodes = myTree.getNumNodes();
1337 
1338  if (nnodes == 0)
1339  return 0;
1340 
1341  struct StackEntry
1342  {
1343  uint myNode;
1344  float myDistSquared;
1345 
1346  SYS_FORCE_INLINE StackEntry() noexcept {}
1347  SYS_FORCE_INLINE StackEntry(uint node, float d2) noexcept
1348  : myNode(node)
1349  , myDistSquared(d2)
1350  {}
1351  };
1352 
1353  // Be careful, because this is a fairly big buffer on the stack,
1354  // and there's the potential to recurse into packed primitives.
1355  // If we have deeply nested packed primitives, that could be an issue.
1357  stack.append(StackEntry(NodeType::markInternal(0),(!farthest) ? 0 : std::numeric_limits<float>::max()));
1358 
1359  do
1360  {
1361  StackEntry entry = stack.last();
1362  stack.removeLast();
1363 
1364  uint next_node = entry.myNode;
1365  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1366  if ((!farthest) ? (entry.myDistSquared > max_dist_squared) : (entry.myDistSquared < max_dist_squared))
1367  continue;
1368 
1369  while (true)
1370  {
1371  if (NodeType::isInternal(next_node))
1372  {
1373  if (next_node == NodeType::EMPTY)
1374  break;
1375 
1376  next_node = NodeType::getInternalNum(next_node);
1377  const BoxType &box = myNodeBoxes[next_node];
1378  v4uf dist2 = (!farthest) ? box.minDistance2(vorigin) : box.maxDistance2(vorigin);
1379  v4uu hit_mask = (!farthest) ? (dist2 <= max_dist_squared) : (dist2 >= max_dist_squared);
1380  const uint hit_bits = _mm_movemask_ps(V4SF(hit_mask.vector));
1381  if (hit_bits == 0)
1382  break;
1383  const NodeType &node = nodes[next_node];
1384  if (!(hit_bits & (hit_bits-1)))
1385  {
1386  // Only 1 bit set
1387  uint local_index = SYSfirstBitSet(hit_bits);
1388  next_node = node.child[local_index];
1389  continue;
1390  }
1391 
1392  exint stack_size = stack.size();
1393  StackEntry *stack_last = stack.data()+stack_size-1;
1394 
1395  // If we're going to be adding to the stack, we might as
1396  // well prune anything from the end of the stack that's
1397  // too far, to possibly reduce reallocations.
1398  // That said, this probably won't happen often, since
1399  // it requires hitting 2 child boxes in the current node
1400  // when the next node in the stack must be farther than an
1401  // existing hit.
1402  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1403  while (stack_size != 0 && ((!farthest) ? (stack_last->myDistSquared > max_dist_squared) : (stack_last->myDistSquared < max_dist_squared)))
1404  {
1405  --stack_size;
1406  --stack_last;
1407  stack.removeLast();
1408  }
1409  static constexpr uint two_bit_indices[16][2] = {
1410  {4, 4}, {4, 4}, {4, 4}, {0, 1},
1411  {4, 4}, {0, 2}, {1, 2}, {0, 1},
1412  {4, 4}, {0, 3}, {1, 3}, {0, 1},
1413  {2, 3}, {0, 2}, {1, 2}, {0, 1}
1414  };
1415  static constexpr uint third_bit_index[16] = {
1416  4, 4, 4, 4,
1417  4, 4, 4, 2,
1418  4, 4, 4, 3,
1419  4, 3, 3, 2
1420  };
1421  // When farthest is true, these are tmax's.
1422  union { v4sf d2v; float d2s[4]; };
1423  d2v = dist2.vector;
1424  uint local_index0 = two_bit_indices[hit_bits][0];
1425  uint local_index1 = two_bit_indices[hit_bits][1];
1426  if (third_bit_index[hit_bits] == 4)
1427  {
1428  // Only 2 bits set
1429  float d20 = d2s[local_index0];
1430  float d21 = d2s[local_index1];
1431  uint child0 = node.child[local_index0];
1432  uint child1 = node.child[local_index1];
1433  if ((!farthest) ? (d20 > d21) : (d20 < d21))
1434  {
1435  uint childtmp = child0;
1436  child0 = child1;
1437  child1 = childtmp;
1438  float tmp = d20;
1439  d20 = d21;
1440  d21 = tmp;
1441  }
1442 
1443  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d20) : (stack_last->myDistSquared <= d20)))
1444  {
1445  next_node = child0;
1446 
1447  // Inserting d21
1448  // Check end of stack first, since it's most likely that the box will go near the end.
1449  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d21) : (stack_last->myDistSquared <= d21)))
1450  {
1451  stack.append(StackEntry(child1, d21));
1452  }
1453  else
1454  {
1455  // Insert in sorted order, but go back at most a constant
1456  // number of entries, to avoid n^2 behaviour.
1457  exint i;
1458  exint limiti = SYSmax(0, stack_size-64);
1459  for (i = stack_size-2; i >= limiti; --i)
1460  {
1461  if ((!farthest) ? (stack[i].myDistSquared >= d21) : (stack[i].myDistSquared <= d21))
1462  {
1463  stack.insert(StackEntry(child1, d21), i+1);
1464  break;
1465  }
1466  }
1467  if (i < limiti)
1468  {
1469  stack.insert(StackEntry(child1, d21), i+1);
1470  }
1471  }
1472  }
1473  else
1474  {
1475  next_node = stack_last->myNode;
1476  stack_last->myNode = child1;
1477  stack_last->myDistSquared = d21;
1478  stack.append(StackEntry(child0, d20));
1479  }
1480  continue;
1481  }
1482 
1483  // 3-4 bits set
1484  uint nhit = (hit_bits == 0xF) ? 4 : 3;
1485  uint local_index2 = third_bit_index[hit_bits];
1486  uint children[BVH_N] = {
1487  node.child[local_index0],
1488  node.child[local_index1],
1489  node.child[local_index2],
1490  node.child[3]
1491  };
1492  d2s[0] = d2s[local_index0];
1493  d2s[1] = d2s[local_index1];
1494  d2s[2] = d2s[local_index2];
1495  //d2s[3] = d2s[3];
1496 
1497  float new_d2;
1498  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d2s[0]) : (stack_last->myDistSquared <= d2s[0])))
1499  {
1500  new_d2 = d2s[0];
1501  next_node = children[0];
1502  }
1503  else
1504  {
1505  new_d2 = stack_last->myDistSquared;
1506  next_node = stack_last->myNode;
1507  stack_last->myDistSquared = d2s[0];
1508  stack_last->myNode = children[0];
1509  }
1510  for (uint hit = 1; hit < nhit; ++hit)
1511  {
1512  float d2 = d2s[hit];
1513  uint child = children[hit];
1514  if ((!farthest) ? (d2 < new_d2) : (d2 > new_d2))
1515  {
1516  float tmpd2 = new_d2;
1517  uint tmpchild = next_node;
1518  new_d2 = d2;
1519  next_node = child;
1520  d2 = tmpd2;
1521  child = tmpchild;
1522  }
1523 
1524  // Check end of stack first, since it's most likely that the box will go near the end.
1525  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d2) : (stack_last->myDistSquared <= d2)))
1526  {
1527  stack.append(StackEntry(child, d2));
1528  }
1529  else
1530  {
1531  // Insert in sorted order, but go back at most a constant
1532  // number of entries, to avoid n^2 behaviour.
1533  exint i;
1534  exint limiti = SYSmax(0, stack_size-64);
1535  for (i = stack_size-2; i >= limiti; --i)
1536  {
1537  if ((!farthest) ? (stack[i].myDistSquared >= d2) : (stack[i].myDistSquared <= d2))
1538  {
1539  stack.insert(StackEntry(child, d2), i+1);
1540  break;
1541  }
1542  }
1543  if (i < limiti)
1544  {
1545  stack.insert(StackEntry(child, d2), i+1);
1546  }
1547  }
1548  stack_last = stack.data()+stack_size;
1549  ++stack_size;
1550  }
1551  continue;
1552  }
1553  op(max_dist_squared, next_node);
1554  break;
1555  }
1556  } while (!stack.isEmpty());
1557 
1558  return 1;
1559 }
1560 
1561 template<uint NAXES,typename SUBCLASS>
1562 template<bool farthest>
1564  const VectorType &origin,
1565  float max_dist_squared) const noexcept
1566 {
1567  hit_info.clear();
1568 
1569  if (!origin.isFinite())
1570  return;
1571 
1573  for (uint axis = 0; axis < NAXES; ++axis)
1574  {
1575  vorigin[axis] = v4uf(origin[axis]);
1576  }
1577 
1578  auto record_hit = [&hit_info](const auto index,
1579  const auto d2,
1580  const auto &pos,
1581  const auto &uvw,
1582  const UT_Array<exint> *nested_indices = nullptr)
1583  {
1584  MinInfo hit;
1585  hit.myItemIndex = index;
1586  // when farthest is true, max_dist_squared is actually a minimum distance squared.
1587  hit.myDistSquared = d2;
1588  hit.myP = pos;
1589  hit.myUVW = uvw;
1590  if (nested_indices)
1591  hit.myNestedItemIndices = new UT_Array<exint>(*nested_indices);
1592  hit_info.emplace_back(hit);
1593  };
1594 
1595  // Record the hit if it satisfies the given distance criteria.
1596  auto add_hit = [&](auto &max_dist_sq, auto index)
1597  {
1598  if (!SUBCLASS::theHasPrimitives || index < numPoints())
1599  {
1600  // Points as spheres
1601  // The point tree subclass reorders myPositions and myRadii
1602  // to match the indices in the tree, so we don't need to remap them.
1603  exint ptarrayindex = (SUBCLASS::theReordersPositions) ? exint(index)
1604  : exint(myPoints(index));
1605  const bool use_pos_array = !myPositions.isEmpty();
1606  const VectorType pos = use_pos_array ? myPositions[ptarrayindex]
1607  : myPosAttrib.get(GA_Offset(ptarrayindex));
1608 
1609  float radius;
1610  if (myRadii.isEmpty())
1611  radius = myRadAttrib.isValid() ? myRadAttrib.get(GA_Offset(ptarrayindex)) : 0.0f;
1612  else
1613  radius = ((myRadii.size() == 1) ? myRadii[0] : myRadii[ptarrayindex]);
1614  VectorType displacement = origin - pos;
1615  float d2 = displacement.length2();
1616  if (radius == 0)
1617  {
1618  // Zero radius
1619  // When farthest is true, max_dist_sq is actually a minimum distance squared.
1620  if ((!farthest) ? (d2 < max_dist_sq) : (d2 > max_dist_sq))
1621  record_hit(index, d2, pos, UT_Vector3(0, 0, 0));
1622  }
1623  else
1624  {
1625  float distance = SYSsqrt(d2) - SYSabs(radius);
1626  d2 = distance * distance;
1627  if ((!farthest) ? (d2 < max_dist_sq) : (d2 > max_dist_sq))
1628  {
1629  VectorType normal = displacement;
1630  normal.normalize();
1631  // Real normal is opposite the displacement if radius is negative.
1632  VectorType real_normal = (((radius > 0) != farthest) ? normal : -normal);
1633  UT_Vector3 hit_uvw;
1634  hit_uvw[0] = real_normal[0];
1635  hit_uvw[1] = real_normal[1];
1636  hit_uvw[2] = (NAXES == 3) ? real_normal[2] : 0;
1637 
1638  // hit position needs to use normal in the direction of displacement.
1639  VectorType hit_pos = pos;
1640  if (!farthest)
1641  hit_pos -= radius * normal;
1642  else
1643  hit_pos += radius * normal;
1644  record_hit(index, d2, hit_pos, hit_uvw);
1645  }
1646  }
1647  }
1648  else
1649  {
1650  // dummy variables to prevent comparison
1651  UT_Vector3 hit_uvw;
1652  exint hit_index = -1;
1653  VectorType hit_position;
1654 
1655  UT_Array<exint> nesting_array;
1656  UT_Array<exint>* nesting_array_ptr = &nesting_array;
1657  exint nesting_array_base = 0;
1658  float d2 = max_dist_sq;
1659  subclass()->template closestPrim<farthest>(
1660  index, origin, d2,
1661  hit_index, hit_uvw, hit_position,
1662  vorigin, nesting_array_ptr, nesting_array_base);
1663  if ((!farthest) ? (d2 < max_dist_sq) : (d2 > max_dist_sq))
1664  record_hit(hit_index, d2, hit_position, hit_uvw, nesting_array_ptr);
1665  }
1666  };
1667  traverseBVH<farthest>(vorigin, max_dist_squared, add_hit);
1668 }
1669 
1670 template<uint NAXES,typename SUBCLASS>
1671 void BVHBase<NAXES,SUBCLASS>::getIntersectingBoxes(const SingleBoxType &query_box, UT_Array<exint> &box_indices) const noexcept
1672 {
1674  UT::getIntersectingBoxes(myTree, myNodeBoxes.get(), query_box, box_indices, stack);
1675 }
1676 
1677 template<uint NAXES,typename SUBCLASS>
1678 template<bool normalize>
1680 {
1681  if (!SUBCLASS::theHasPrimitives || hit_info.myItemIndex < numPoints())
1682  {
1683  // NOTE: We don't need to negate if the radius is negative, because
1684  // that was automatically done in sendRay by multiplying by invradius.
1685  return VectorType(hit_info.myUVW);
1686  }
1687  return subclass()->template primGeometricNormal<normalize>(hit_info);
1688 }
1689 
1690 template<uint NAXES,typename SUBCLASS>
1691 void BVHBase<NAXES,SUBCLASS>::getDerivs(const CommonHitInfo &hit_info, VectorType &dP_du, VectorType &dP_dv) const noexcept
1692 {
1693  if (!SUBCLASS::theHasPrimitives || hit_info.myItemIndex < numPoints())
1694  {
1695  // NOTE: We don't need to negate nml if the radius is negative, because
1696  // that was automatically done in sendRay by multiplying by invradius.
1697  // TODO: However, do we need to negate dP_du or dP_dv?
1698  VectorType nml;
1699  nml[0] = hit_info.myUVW[0];
1700  nml[1] = hit_info.myUVW[1];
1701  if (NAXES == 3)
1702  {
1703  nml[2] = hit_info.myUVW[1];
1704  UT_Vector2 nmlxy(nml[0], nml[1]);
1705  float lengthxy = nmlxy.normalize();
1706 
1707  dP_dv[0] = -nml[2]*nmlxy[0];
1708  dP_dv[1] = -nml[2]*nmlxy[1];
1709  dP_dv[2] = lengthxy;
1710  dP_dv *= M_PI;
1711 
1712  dP_du[0] = -nml[1]*(2*M_PI);
1713  dP_du[1] = nml[0]*(2*M_PI);
1714  dP_du[2] = 0;
1715  }
1716  else
1717  {
1718  UT_ASSERT(NAXES==2);
1719  // FIXME: Verify that the sign is correct on this!
1720  dP_du[0] = -nml[1]*(2*M_PI);
1721  dP_du[1] = nml[0]*(2*M_PI);
1722  dP_dv[0] = 0;
1723  dP_dv[1] = 0;
1724  }
1725  return;
1726  }
1727  subclass()->primDerivs(hit_info, dP_du, dP_dv);
1728 }
1729 
1730 template<uint NAXES,typename SUBCLASS>
1732 {
1733  float u = SYSatan(uvw[1], uvw[0]) / (float)(2*M_PI);
1734  if (u < 0)
1735  u += 1;
1736  if (NAXES == 3)
1737  {
1738  float v = SYSacos(uvw[2]) / (float)M_PI;
1739  uvw[0] = u;
1740  uvw[1] = v;
1741  uvw[2] = 0;
1742  }
1743  else
1744  {
1745  UT_ASSERT(NAXES==2);
1746  uvw[0] = u;
1747  uvw[1] = 0;
1748  }
1749 }
1750 
1751 template<uint NAXES,typename SUBCLASS>
1752 template<GA_AttributeOwner owner,typename T,typename DEST_T>
1753 bool BVHBase<NAXES,SUBCLASS>::getAttribute(const CommonHitInfo &hit_info, const GA_ROHandleT<T> &attrib, const GEO_Detail &detail, DEST_T &value) const noexcept
1754 {
1755  UT_ASSERT(owner == attrib->getOwner());
1756 
1757  if (owner == GA_ATTRIB_DETAIL)
1758  {
1759  value = attrib.get(GA_DETAIL_OFFSET);
1760  return true;
1761  }
1762 
1763  exint index = hit_info.myItemIndex;
1764  if (!SUBCLASS::theHasPrimitives || index < numPoints())
1765  {
1766  if (owner != GA_ATTRIB_POINT)
1767  return false;
1768 
1769  GA_Offset ptoff = myPoints(index);
1770  value = attrib.get(ptoff);
1771  return true;
1772  }
1773  return subclass()->template primAttribute<owner,T,DEST_T>(hit_info, attrib, detail, value);
1774 }
1775 
1776 } // GEO namespace
1777 
1778 #undef GEO_BVH_INTERLEAVED
#define SYSmax(a, b)
Definition: SYS_Math.h:1952
T & last()
Definition: UT_Array.h:840
SYS_FORCE_INLINE void setNestingArrayInto(HitInfo &hit_info) noexcept
Definition: GEO_BVHImpl.h:108
SYS_FORCE_INLINE UT_Vector3 & lastUVW() noexcept
Definition: GEO_BVHImpl.h:126
#define SYS_STATIC_ASSERT(expr)
SYS_FORCE_INLINE void insertHit(const UT_Vector3 &hit_uvw, const float t, const uint index, float &limit_t) noexcept
Definition: GEO_BVHImpl.h:285
void sendRay(const VectorType &origin, const VectorType &direction, HitInfoType &hit_info, float tmin=0, float tmax=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:348
SYS_FORCE_INLINE UT_Array< exint > * nestingArray() noexcept
Definition: GEO_BVHImpl.h:173
SYS_FORCE_INLINE UT_Array< HitInfo > * getHitArray() noexcept
Definition: GEO_BVHImpl.h:124
SIM_API const UT_StringHolder angle
#define SYS_STATIC_ASSERT_MSG(expr, msg)
void getDerivs(const CommonHitInfo &hit_info, VectorType &dP_du, VectorType &dP_dv) const noexcept
Fills in the values of dP/du and dP/dv for the hit surface.
Definition: GEO_BVHImpl.h:1691
Definition: UT_BVH.h:37
void findClosest(VectorType origin, MinInfo &min_info, float max_dist_squared=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:1195
SYS_FORCE_INLINE void removeLast()
Definition: UT_Array.h:383
VectorType getGeometricNormal(const CommonHitInfo &hit_info) const noexcept
const GLdouble * v
Definition: glcorearb.h:837
SYS_FORCE_INLINE exint nestingArrayBase() noexcept
Definition: GEO_BVHImpl.h:116
#define M_PI
Definition: fmath.h:98
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
SYS_FORCE_INLINE UT_Array< HitInfoAndNormal > * getHitArray() noexcept
Definition: GEO_BVHImpl.h:187
SYS_FORCE_INLINE void noHit() noexcept
Definition: GEO_BVHImpl.h:148
SYS_FORCE_INLINE void setNestingArrayInto(HitInfoAndNormal &hit_info) noexcept
Definition: GEO_BVHImpl.h:315
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool SYSisFinite(fpreal64 f)
Definition: SYS_Math.h:259
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:719
UT_Array< exint > *const myNestingTempArray
Definition: GEO_BVHImpl.h:267
SYS_FORCE_INLINE VectorType getNormal(const HitInfoAndNormal &hit_info) const noexcept
Definition: GEO_BVHImpl.h:320
UT_Vector3T< float > UT_Vector3
int64 exint
Definition: SYS_Types.h:125
SYS_FORCE_INLINE exint nestingArrayBase() const noexcept
Definition: GEO_BVHImpl.h:125
SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
Definition: GEO_BVHImpl.h:122
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
#define SYSabs(a)
Definition: SYS_Math.h:1954
PUGI__FN void reverse(I begin, I end)
Definition: pugixml.cpp:7458
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7550
SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
Definition: GEO_BVHImpl.h:322
void findClosestInCone(VectorType origin, VectorType direction, const float angle, const exint max_points, const float max_dist_squared, UT::BVHOrderedStack &output_queue) const noexcept
Definition: GEO_BVHImpl.h:1103
#define UT_ASSERT_MSG_P(ZZ,...)
Definition: UT_Assert.h:167
void findClosestToSegment(VectorType p0, VectorType p1, const exint max_points, const float max_dist_squared, UT::BVHOrderedStack &output_queue) const noexcept
Finds the closest points to the line segment with endpoints p0 and p1.
Definition: GEO_BVHImpl.h:1084
SYS_FORCE_INLINE const VectorType & getNormal(const HitInfoAndNormal &hit_info) const noexcept
Definition: GEO_BVHImpl.h:177
SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
Definition: GEO_BVHImpl.h:179
SYS_FORCE_INLINE UT_Array< exint > * nestingArray() noexcept
Definition: GEO_BVHImpl.h:316
exint size() const
Definition: UT_Array.h:667
uint64 value_type
Definition: GA_PrimCompat.h:29
SYS_FORCE_INLINE void setNormal(HitInfoAndNormal &hit_info, const VectorType &nml) const noexcept
Definition: GEO_BVHImpl.h:183
UT_Array< HitInfoAndNormal > & myHitInfo
Definition: GEO_BVHImpl.h:341
GEO::BVHBase< NAXES, SUBCLASS > BVHBase
Definition: GU_BVH.h:31
SYS_FORCE_INLINE T minDistance2(const UT_FixedVector< T, NAXES > &p) const noexcept
Definition: UT_BVH.h:313
#define UT_ASSERT_MSG(ZZ,...)
Definition: UT_Assert.h:168
GA_Size GA_Offset
Definition: GA_Types.h:653
SYS_FORCE_INLINE AllHitsAndNormalsFunctor(UT_Array< HitInfoAndNormal > &hit_info, UT_Array< exint > *nesting_temp_array) noexcept
Definition: GEO_BVHImpl.h:275
SYS_FORCE_INLINE void setNormal(HitInfo &hit_info, const VectorType &nml) const noexcept
Definition: GEO_BVHImpl.h:123
GLdouble n
Definition: glcorearb.h:2008
bool getAttribute(const CommonHitInfo &hit_info, const GA_ROHandleT< T > &attrib, const GEO_Detail &detail, DEST_T &value) const noexcept
Definition: GEO_BVHImpl.h:1753
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
void findClosestToLine(VectorType origin, VectorType direction, const exint max_points, const float max_dist_squared, UT::BVHOrderedStack &output_queue) const noexcept
Finds the closest points to the infinite line containing origin with direction direction.
Definition: GEO_BVHImpl.h:1065
SYS_FORCE_INLINE UT_Array< HitInfo > * getHitArray() noexcept
Definition: GEO_BVHImpl.h:255
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:781
SYS_FORCE_INLINE UT_Array< exint > * nestingArray() noexcept
Definition: GEO_BVHImpl.h:112
SYS_FORCE_INLINE UT_Array< HitInfoAndNormal > * getHitArray() noexcept
Definition: GEO_BVHImpl.h:330
SYS_FORCE_INLINE UT_Vector3 & lastUVW() noexcept
Definition: GEO_BVHImpl.h:189
SYS_FORCE_INLINE VectorType getNormal(const HitInfo &hit_info) const noexcept
Definition: GEO_BVHImpl.h:120
void getIntersectingBoxes(const SingleBoxType &query_box, UT_Array< exint > &box_indices) const noexcept
Definition: GEO_BVHImpl.h:1671
SYS_FORCE_INLINE T maxDistance2(const UT_FixedVector< T, NAXES > &p) const noexcept
Definition: UT_BVH.h:326
Definition: VM_SIMD.h:48
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:138
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_FORCE_INLINE void noHit() noexcept
Definition: GEO_BVHImpl.h:212
Definition: VM_SIMD.h:188
int traverseBVH(const UT_FixedVector< v4uf, NAXES > &vorigin, float &max_dist_squared, FUNC &op) const noexcept
Definition: GEO_BVHImpl.h:1330
void clear() noexcept
Definition: GEO_BVHImpl.h:34
typename SYS_SelectType< UT_FixedVector< uint, 2 >, UT_FixedVector< uint, 3 >, NAXES==3 >::type UintVectorType
Definition: GEO_BVH.h:40
static void pointUVWToPolar(VectorType &uvw) noexcept
Definition: GEO_BVHImpl.h:1731
SYS_FORCE_INLINE void insertHit(const UT_Vector3 &hit_uvw, const float t, const uint index, float &limit_t) noexcept
Definition: GEO_BVHImpl.h:216
void sendRayAllRad(const VectorType &origin, const VectorType &direction, UT_Array< HitInfoType > &hit_info, float default_radius, UT_Array< exint > *nesting_temp_array=nullptr, float duplicate_tolerance=0, float tmin=0, float tmax=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:428
SYS_FORCE_INLINE exint nestingArrayBase() const noexcept
Definition: GEO_BVHImpl.h:331
IMATH_HOSTDEVICE constexpr int sign(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:33
SYS_FORCE_INLINE exint nestingArrayBase() const noexcept
Definition: GEO_BVHImpl.h:188
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
T vals[NAXES][2]
Definition: UT_BVH.h:39
exint append()
Definition: UT_Array.h:142
GLdouble t
Definition: glad.h:2397
SYS_FORCE_INLINE void setNestingArrayInto(HitInfoAndNormal &hit_info) noexcept
Definition: GEO_BVHImpl.h:169
SYS_FORCE_INLINE VectorType getNormal(const HitInfo &hit_info) const noexcept
Definition: GEO_BVHImpl.h:251
void sendRayGeneric(VectorType origin, VectorType direction, FUNCTOR &hit_info, float tmin=0, float tmax=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:483
SYS_FORCE_INLINE void setNormal(HitInfoAndNormal &hit_info, const VectorType &nml) const noexcept
Definition: GEO_BVHImpl.h:326
void assign(T xx=0.0f, T yy=0.0f, T zz=0.0f)
Set the values of the vector components.
Definition: UT_Vector3.h:696
IMATH_NAMESPACE::V2f IMATH_NAMESPACE::Box2i std::string this attribute is obsolete as of OpenEXR v3 float
SYS_FORCE_INLINE void intersectTol(T &box_tmin, T &box_tmax, const UT_FixedVector< uint, NAXES > &signs, const UT_FixedVector< T, NAXES > &origin, const UT_FixedVector< T, NAXES > &inverse_direction, T tolerance) const noexcept
Intersect the box expanded by the specified tolerance in all axes.
Definition: UT_BVH.h:284
SYS_FORCE_INLINE void setNormal(HitInfo &hit_info, const VectorType &nml) const noexcept
Definition: GEO_BVHImpl.h:254
T * data()
Definition: UT_Array.h:866
typename SYS_SelectType< UT_Vector2, UT_Vector3, NAXES==3 >::type VectorType
Definition: GEO_BVH.h:39
v4si vector
Definition: VM_SIMD.h:185
GLuint index
Definition: glcorearb.h:786
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
SYS_FORCE_INLINE UT_Array< exint > * nestingArray() noexcept
Definition: GEO_BVHImpl.h:247
if(num_boxed_items<=0)
Definition: UT_RTreeImpl.h:697
SYS_FORCE_INLINE void intersect(T &box_tmin, T &box_tmax, const UT_FixedVector< uint, NAXES > &signs, const UT_FixedVector< T, NAXES > &origin, const UT_FixedVector< T, NAXES > &inverse_direction) const noexcept
Definition: UT_BVH.h:267
void findMaximalPointsCommon(const QUERY_POINT &query_point, UT::BVHOrderedStack &stack, UT::BVHOrderedStack &output_queue, exint max_points, float max_dist_squared) const noexcept
Definition: GEO_BVHImpl.h:992
SYS_FORCE_INLINE AllHitsFunctor(UT_Array< HitInfo > &hit_info, UT_Array< exint > *nesting_temp_array) noexcept
Definition: GEO_BVHImpl.h:206
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
void getIntersectingBoxes(const UT::BVH< 4 > &bvh, const UT::Box< v4uf, NAXES > *node_boxes, const UT::Box< float, NAXES > &query_box, UT_Array< INT_TYPE > &box_indices, BVHUnorderedStack &stack) noexcept
Definition: UT_BVHImpl.h:2449
#define V4SF(A)
Definition: VM_BasicFunc.h:68
SYS_FORCE_INLINE SingleHitFunctor(HitInfo &hit_info) noexcept
Definition: GEO_BVHImpl.h:82
#define GA_DETAIL_OFFSET
Definition: GA_Types.h:698
SIM_API const UT_StringHolder distance
void sendRayAll(const VectorType &origin, const VectorType &direction, UT_Array< HitInfoType > &hit_info, UT_Array< exint > *nesting_temp_array=nullptr, float duplicate_tolerance=0, float tmin=0, float tmax=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:382
SYS_FORCE_INLINE SingleHitAndNormalFunctor(HitInfoAndNormal &hit_info) noexcept
Definition: GEO_BVHImpl.h:143
#define SYSmin(a, b)
Definition: SYS_Math.h:1953
SYS_FORCE_INLINE UT_Vector3 & lastUVW() noexcept
Definition: GEO_BVHImpl.h:257
SYS_FORCE_INLINE UT_StorageMathFloat_t< T > normalize() noexcept
Definition: UT_Vector2.h:312
SYS_FORCE_INLINE void insertHit(const UT_Vector3 &hit_uvw, const float t, const uint index, float &limit_t, bool should_clear_nesting=true) noexcept
Definition: GEO_BVHImpl.h:93
unsigned int uint
Definition: SYS_Types.h:45
void sendRayRad(const VectorType &origin, const VectorType &direction, HitInfoType &hit_info, float default_radius, float tmin=0, float tmax=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:361
SYS_FORCE_INLINE exint nestingArrayBase() const noexcept
Definition: GEO_BVHImpl.h:256
UT_Array< exint > * myNestedItemIndices
This can be used for packed primitive hits.
Definition: GEO_BVH.h:68
SYS_FORCE_INLINE void noHit() noexcept
Definition: GEO_BVHImpl.h:281
v4sf vector
Definition: VM_SIMD.h:348
exint insert(exint index)
Definition: UT_ArrayImpl.h:733
SYS_FORCE_INLINE void noHit() noexcept
Definition: GEO_BVHImpl.h:87
SYS_FORCE_INLINE void insertHit(const UT_Vector3 &hit_uvw, const float t, const uint index, float &limit_t, bool should_clear_nesting=true) noexcept
Definition: GEO_BVHImpl.h:154
UT_Array< HitInfo > & myHitInfo
Definition: GEO_BVHImpl.h:266
void findProximity(UT_Array< MinInfo > &min_info, const VectorType &origin, float max_dist_squared=std::numeric_limits< float >::max()) const noexcept
Definition: GEO_BVHImpl.h:1563
SYS_FORCE_INLINE void setNormal(const VectorType &nml) noexcept
Definition: GEO_BVHImpl.h:253
SYS_FORCE_INLINE UT_Vector3 & lastUVW() noexcept
Definition: GEO_BVHImpl.h:332
SYS_FORCE_INLINE void setNestingArrayInto(HitInfo &hit_info) noexcept
Definition: GEO_BVHImpl.h:246
UT_Array< exint > *const myNestingTempArray
Definition: GEO_BVHImpl.h:342
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
Definition: UT_Array.h:671
VectorType myP
Definition: GEO_BVH.h:146