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  using NodeType = typename UT_BVH<BVH_N>::Node;
1198  const NodeType *nodes = myTree.getNodes();
1199  const uint nnodes = myTree.getNumNodes();
1200 
1201  if (nnodes == 0 || !origin.isFinite())
1202  {
1203  // Nothing to hit
1204  hit_info.myItemIndex = -1;
1205  hit_info.myUVW.assign(0,0,0);
1206  hit_info.myDistSquared = -1.0f;
1207  hit_info.myP = VectorType(typename VectorType::value_type(0));
1208  return;
1209  }
1210 
1211  UT_Array<exint> *nesting_array = hit_info.myNestedItemIndices;
1212  exint nesting_array_base = nesting_array ? nesting_array->size() : 0;
1213 
1214  const uint num_points = numPoints();
1215 
1216  struct StackEntry
1217  {
1218  uint myNode;
1219  float myDistSquared;
1220 
1221  SYS_FORCE_INLINE StackEntry() noexcept {}
1222  SYS_FORCE_INLINE StackEntry(uint node, float d2) noexcept
1223  : myNode(node)
1224  , myDistSquared(d2)
1225  {}
1226  };
1227 
1228 #if GEO_BVH_INTERLEAVED
1230  for (uint axis = 0; axis < NAXES; ++axis)
1231  {
1232  vorigin[axis] = v4uf(origin[axis]);
1233  }
1234 #else
1235  const BoxType &box = myNodeBoxes[0];
1236  float dist2 = (!farthest) ? box.minDistance2(origin) : box.maxDistance2(origin);
1237 
1238  // NOTE: When farthest is true, max_dist_squared is actually a minimum distance squared.
1239  if ((!farthest) ? (dist2 > max_dist_squared) : (dist2 < max_dist_squared))
1240  {
1241  // No hits
1242  hit_info.myItemIndex = -1;
1243  hit_info.myUVW.assign(0,0,0);
1244  hit_info.myDistSquared = -1.0f;
1245  hit_info.myP = VectorType(typename VectorType::value_type(0));
1246  return;
1247  }
1248 #endif
1249 
1250  UT_Vector3 hit_uvw;
1251  exint hit_index = -1;
1252  VectorType hit_position;
1253 
1254  // Be careful, because this is a fairly big buffer on the stack,
1255  // and there's the potential to recurse into packed primitives.
1256  // If we have deeply nested packed primitives, that could be an issue.
1258 #if GEO_BVH_INTERLEAVED
1259  stack.append(StackEntry(NodeType::markInternal(0),(!farthest) ? 0 : std::numeric_limits<float>::max()));
1260 #else
1261  stack.append(StackEntry(0,dist2));
1262 #endif
1263 
1264  do
1265  {
1266  StackEntry entry = stack.last();
1267  stack.removeLast();
1268 
1269  uint next_node = entry.myNode;
1270  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1271  if ((!farthest) ? (entry.myDistSquared > max_dist_squared) : (entry.myDistSquared < max_dist_squared))
1272  continue;
1273 
1274  while (true)
1275  {
1276 #if GEO_BVH_INTERLEAVED
1277  if (NodeType::isInternal(next_node))
1278  {
1279  if (next_node == NodeType::EMPTY)
1280  break;
1281 
1282  next_node = NodeType::getInternalNum(next_node);
1283  const BoxType &box = myNodeBoxes[next_node];
1284  v4uf dist2 = (!farthest) ? box.minDistance2(vorigin) : box.maxDistance2(vorigin);
1285  v4uu hit_mask = (!farthest) ? (dist2 <= max_dist_squared) : (dist2 >= max_dist_squared);
1286  const uint hit_bits = _mm_movemask_ps(V4SF(hit_mask.vector));
1287  if (hit_bits == 0)
1288  break;
1289  const NodeType &node = nodes[next_node];
1290  if (!(hit_bits & (hit_bits-1)))
1291  {
1292  // Only 1 bit set
1293  uint local_index = SYSfirstBitSet(hit_bits);
1294 #if 1
1295  next_node = node.child[local_index];
1296 #else
1297  float local_d2 = d2s[local_index];
1298  uint child_index = node.child[local_index];
1299  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= local_d2) : (stack_last->myDistSquared <= local_d2)))
1300  next_node = child_index;
1301  else
1302  {
1303  next_node = stack_last->myNode;
1304  stack_last->myNode = child_index;
1305  stack_last->myDistSquared = local_d2;
1306  }
1307 #endif
1308  continue;
1309  }
1310 
1311  exint stack_size = stack.size();
1312  StackEntry *stack_last = stack.data()+stack_size-1;
1313 
1314  // If we're going to be adding to the stack, we might as
1315  // well prune anything from the end of the stack that's
1316  // too far, to possibly reduce reallocations.
1317  // That said, this probably won't happen often, since
1318  // it requires hitting 2 child boxes in the current node
1319  // when the next node in the stack must be farther than an
1320  // existing hit.
1321  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1322  while (stack_size != 0 && ((!farthest) ? (stack_last->myDistSquared > max_dist_squared) : (stack_last->myDistSquared < max_dist_squared)))
1323  {
1324  --stack_size;
1325  --stack_last;
1326  stack.removeLast();
1327  }
1328  static constexpr uint two_bit_indices[16][2] = {
1329  {4, 4}, {4, 4}, {4, 4}, {0, 1},
1330  {4, 4}, {0, 2}, {1, 2}, {0, 1},
1331  {4, 4}, {0, 3}, {1, 3}, {0, 1},
1332  {2, 3}, {0, 2}, {1, 2}, {0, 1}
1333  };
1334  static constexpr uint third_bit_index[16] = {
1335  4, 4, 4, 4,
1336  4, 4, 4, 2,
1337  4, 4, 4, 3,
1338  4, 3, 3, 2
1339  };
1340  // When farthest is true, these are tmax's.
1341  union { v4sf d2v; float d2s[4]; };
1342  d2v = dist2.vector;
1343  uint local_index0 = two_bit_indices[hit_bits][0];
1344  uint local_index1 = two_bit_indices[hit_bits][1];
1345  if (third_bit_index[hit_bits] == 4)
1346  {
1347  // Only 2 bits set
1348  float d20 = d2s[local_index0];
1349  float d21 = d2s[local_index1];
1350  uint child0 = node.child[local_index0];
1351  uint child1 = node.child[local_index1];
1352  if ((!farthest) ? (d20 > d21) : (d20 < d21))
1353  {
1354  uint childtmp = child0;
1355  child0 = child1;
1356  child1 = childtmp;
1357  float tmp = d20;
1358  d20 = d21;
1359  d21 = tmp;
1360  }
1361 
1362  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d20) : (stack_last->myDistSquared <= d20)))
1363  {
1364  next_node = child0;
1365 
1366  // Inserting d21
1367  // Check end of stack first, since it's most likely that the box will go near the end.
1368  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d21) : (stack_last->myDistSquared <= d21)))
1369  {
1370  stack.append(StackEntry(child1, d21));
1371  }
1372  else
1373  {
1374  // Insert in sorted order, but go back at most a constant
1375  // number of entries, to avoid n^2 behaviour.
1376  exint i;
1377  exint limiti = SYSmax(0, stack_size-64);
1378  for (i = stack_size-2; i >= limiti; --i)
1379  {
1380  if ((!farthest) ? (stack[i].myDistSquared >= d21) : (stack[i].myDistSquared <= d21))
1381  {
1382  stack.insert(StackEntry(child1, d21), i+1);
1383  break;
1384  }
1385  }
1386  if (i < limiti)
1387  {
1388  stack.insert(StackEntry(child1, d21), i+1);
1389  }
1390  }
1391  }
1392  else
1393  {
1394  next_node = stack_last->myNode;
1395  stack_last->myNode = child1;
1396  stack_last->myDistSquared = d21;
1397  stack.append(StackEntry(child0, d20));
1398  }
1399  continue;
1400  }
1401 
1402  // 3-4 bits set
1403  uint nhit = (hit_bits == 0xF) ? 4 : 3;
1404  uint local_index2 = third_bit_index[hit_bits];
1405  uint children[BVH_N] = {
1406  node.child[local_index0],
1407  node.child[local_index1],
1408  node.child[local_index2],
1409  node.child[3]
1410  };
1411  d2s[0] = d2s[local_index0];
1412  d2s[1] = d2s[local_index1];
1413  d2s[2] = d2s[local_index2];
1414  //d2s[3] = d2s[3];
1415 
1416  float new_d2;
1417  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d2s[0]) : (stack_last->myDistSquared <= d2s[0])))
1418  {
1419  new_d2 = d2s[0];
1420  next_node = children[0];
1421  }
1422  else
1423  {
1424  new_d2 = stack_last->myDistSquared;
1425  next_node = stack_last->myNode;
1426  stack_last->myDistSquared = d2s[0];
1427  stack_last->myNode = children[0];
1428  }
1429  for (uint hit = 1; hit < nhit; ++hit)
1430  {
1431  float d2 = d2s[hit];
1432  uint child = children[hit];
1433  if ((!farthest) ? (d2 < new_d2) : (d2 > new_d2))
1434  {
1435  float tmpd2 = new_d2;
1436  uint tmpchild = next_node;
1437  new_d2 = d2;
1438  next_node = child;
1439  d2 = tmpd2;
1440  child = tmpchild;
1441  }
1442 
1443  // Check end of stack first, since it's most likely that the box will go near the end.
1444  if (!stack_size || ((!farthest) ? (stack_last->myDistSquared >= d2) : (stack_last->myDistSquared <= d2)))
1445  {
1446  stack.append(StackEntry(child, d2));
1447  }
1448  else
1449  {
1450  // Insert in sorted order, but go back at most a constant
1451  // number of entries, to avoid n^2 behaviour.
1452  exint i;
1453  exint limiti = SYSmax(0, stack_size-64);
1454  for (i = stack_size-2; i >= limiti; --i)
1455  {
1456  if ((!farthest) ? (stack[i].myDistSquared >= d2) : (stack[i].myDistSquared <= d2))
1457  {
1458  stack.insert(StackEntry(child, d2), i+1);
1459  break;
1460  }
1461  }
1462  if (i < limiti)
1463  {
1464  stack.insert(StackEntry(child, d2), i+1);
1465  }
1466  }
1467  stack_last = stack.data()+stack_size;
1468  ++stack_size;
1469  }
1470  continue;
1471  }
1472  uint index = next_node;//myIndices[next_node];
1473 #else
1474  const NodeType &node = nodes[next_node];
1475  uint children[BVH_N];
1476  float d2s[BVH_N];
1477  uint nnodehits = 0;
1478  for (uint i = 0; i < BVH_N; ++i)
1479  {
1480  const uint itemi = node.child[i];
1481  if (NodeType::isInternal(itemi))
1482  {
1483  if (itemi == NodeType::EMPTY)
1484  continue;
1485 
1486  // Internal node: intersect against box
1487  const uint childi = NodeType::getInternalNum(itemi);
1488  const BoxType &box = myNodeBoxes[childi];
1489  float dist2 = (!farthest) ? box.minDistance2(origin) : box.maxDistance2(origin);
1490  if ((!farthest) ? (dist2 > min_dist_squared) : (dist2 < min_dist_squared))
1491  continue;
1492 
1493  children[nnodehits] = childi;
1494  d2s[nnodehits] = dist2;
1495  ++nnodehits;
1496  }
1497  else
1498  {
1499  // Leaf item: intersect against item
1500  uint index = itemi;//myIndices[itemi];
1501 #endif
1502  if (!SUBCLASS::theHasPrimitives || index < num_points)
1503  {
1504  // Points as spheres
1505  // The point tree subclass reorders myPositions and myRadii
1506  // to match the indices in the tree, so we don't need to remap them.
1507  exint ptarrayindex = (SUBCLASS::theReordersPositions) ? exint(index) : exint(myPoints(index));
1508  const bool use_pos_array = !myPositions.isEmpty();
1509  const VectorType pos = use_pos_array ? myPositions[ptarrayindex] : myPosAttrib.get(GA_Offset(ptarrayindex));
1510  //if (myRadii.isValid())
1511  float radius;
1512  if (myRadii.isEmpty())
1513  radius = myRadAttrib.isValid() ? myRadAttrib.get(GA_Offset(ptarrayindex)) : 0.0f;
1514  else
1515  radius = ((myRadii.size() == 1) ? myRadii[0] : myRadii[ptarrayindex]);
1516  VectorType displacement = origin-pos;
1517  float d2 = displacement.length2();
1518  if (radius == 0)
1519  {
1520  // Zero radius
1521  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1522  if ((!farthest) ? (d2 < max_dist_squared) : (d2 > max_dist_squared))
1523  {
1524  max_dist_squared = d2;
1525  hit_index = index;
1526  hit_uvw.assign(0,0,0);
1527  hit_position = pos;
1528  }
1529  }
1530  else
1531  {
1532  float distance = SYSsqrt(d2) - SYSabs(radius);
1533  d2 = distance*distance;
1534  if ((!farthest) ? (d2 < max_dist_squared) : (d2 > max_dist_squared))
1535  {
1536  max_dist_squared = d2;
1537  hit_index = index;
1538  VectorType normal = displacement;
1539  normal.normalize();
1540  // Real normal is opposite the displacement if radius is negative.
1541  VectorType real_normal = (((radius > 0) != farthest) ? normal : -normal);
1542  hit_uvw[0] = real_normal[0];
1543  hit_uvw[1] = real_normal[1];
1544  hit_uvw[2] = (NAXES==3) ? real_normal[2] : 0;
1545 
1546  // hit_position needs to use normal in the direction of displacement.
1547  hit_position = pos;
1548  if (!farthest)
1549  hit_position -= radius*normal;
1550  else
1551  hit_position += radius*normal;
1552  }
1553  }
1554  }
1555  else
1556  {
1557  subclass()->template closestPrim<farthest>(
1558  index, origin, max_dist_squared,
1559  hit_index, hit_uvw, hit_position,
1560  vorigin, nesting_array, nesting_array_base);
1561  }
1562 #if GEO_BVH_INTERLEAVED
1563  break;
1564 #else
1565  }
1566  }
1567  if (nnodehits == 0)
1568  break;
1569  exint stack_size = stack.size();
1570  StackEntry *stack_last = stack.data()+stack_size-1;
1571  if (nnodehits == 1)
1572  {
1573  uint child_index = children[0];
1574  if (!stack_size || stack_last->myTMin >= tmins[0])
1575  next_node = child_index;
1576  else
1577  {
1578  next_node = stack_last->myNode;
1579  stack_last->myNode = child_index;
1580  stack_last->myTMin = tmins[0];
1581  }
1582  }
1583  else if (BVH_N == 2 || nnodehits == 2)
1584  {
1585  const uint local_index = (tmins[0] >= tmins[1]);
1586  next_node = children[local_index];
1587  const uint insert_node = children[!local_index];
1588  const float insert_tmin = tmins[!local_index];
1589  // Check end of stack first, since it's most likely that the box will go near the end.
1590  if (!stack_size || stack_last->myTMin <= insert_tmin)
1591  {
1592  stack.append(StackEntry(insert_node, insert_tmin));
1593  }
1594  else
1595  {
1596  // Insert in sorted order, but go back at most a constant
1597  // number of entries, to avoid n^2 behaviour.
1598  exint i;
1599  exint limiti = SYSmax(0, stack_size-64);
1600  for (i = stack_size-2; i >= limiti; --i)
1601  {
1602  if (stack[i].myTMin <= insert_tmin)
1603  {
1604  stack.insert(StackEntry(insert_node, insert_tmin), i+1);
1605  break;
1606  }
1607  }
1608  if (i < limiti)
1609  {
1610  stack.insert(StackEntry(insert_node, insert_tmin), i+1);
1611  }
1612  }
1613  }
1614  else
1615  {
1616  // Sort/insert and keep closest
1617  SYS_STATIC_ASSERT_MSG(BVH_N==2, "FIXME: Implement case of BVH_N>2!!!");
1618 
1619  }
1620 #endif
1621  }
1622  } while (!stack.isEmpty());
1623 
1624  if (hit_index >= 0)
1625  {
1626  hit_info.myItemIndex = hit_index;
1627  hit_info.myUVW = hit_uvw;
1628  // When farthest is true, max_dist_squared is actually a minimum distance squared.
1629  hit_info.myDistSquared = max_dist_squared;
1630  hit_info.myP = hit_position;
1631  }
1632  else
1633  {
1634  hit_info.myItemIndex = -1;
1635  hit_info.myUVW.assign(0,0,0);
1636  hit_info.myDistSquared = -1.0f;
1637  hit_info.myP = VectorType(typename VectorType::value_type(0));
1638  }
1639 }
1640 
1641 template<uint NAXES,typename SUBCLASS>
1642 void BVHBase<NAXES,SUBCLASS>::getIntersectingBoxes(const SingleBoxType &query_box, UT_Array<exint> &box_indices) const noexcept
1643 {
1645  UT::getIntersectingBoxes(myTree, myNodeBoxes.get(), query_box, box_indices, stack);
1646 }
1647 
1648 template<uint NAXES,typename SUBCLASS>
1649 template<bool normalize>
1651 {
1652  if (!SUBCLASS::theHasPrimitives || hit_info.myItemIndex < numPoints())
1653  {
1654  // NOTE: We don't need to negate if the radius is negative, because
1655  // that was automatically done in sendRay by multiplying by invradius.
1656  return VectorType(hit_info.myUVW);
1657  }
1658  return subclass()->template primGeometricNormal<normalize>(hit_info);
1659 }
1660 
1661 template<uint NAXES,typename SUBCLASS>
1662 void BVHBase<NAXES,SUBCLASS>::getDerivs(const CommonHitInfo &hit_info, VectorType &dP_du, VectorType &dP_dv) const noexcept
1663 {
1664  if (!SUBCLASS::theHasPrimitives || hit_info.myItemIndex < numPoints())
1665  {
1666  // NOTE: We don't need to negate nml if the radius is negative, because
1667  // that was automatically done in sendRay by multiplying by invradius.
1668  // TODO: However, do we need to negate dP_du or dP_dv?
1669  VectorType nml;
1670  nml[0] = hit_info.myUVW[0];
1671  nml[1] = hit_info.myUVW[1];
1672  if (NAXES == 3)
1673  {
1674  nml[2] = hit_info.myUVW[1];
1675  UT_Vector2 nmlxy(nml[0], nml[1]);
1676  float lengthxy = nmlxy.normalize();
1677 
1678  dP_dv[0] = -nml[2]*nmlxy[0];
1679  dP_dv[1] = -nml[2]*nmlxy[1];
1680  dP_dv[2] = lengthxy;
1681  dP_dv *= M_PI;
1682 
1683  dP_du[0] = -nml[1]*(2*M_PI);
1684  dP_du[1] = nml[0]*(2*M_PI);
1685  dP_du[2] = 0;
1686  }
1687  else
1688  {
1689  UT_ASSERT(NAXES==2);
1690  // FIXME: Verify that the sign is correct on this!
1691  dP_du[0] = -nml[1]*(2*M_PI);
1692  dP_du[1] = nml[0]*(2*M_PI);
1693  dP_dv[0] = 0;
1694  dP_dv[1] = 0;
1695  }
1696  return;
1697  }
1698  subclass()->primDerivs(hit_info, dP_du, dP_dv);
1699 }
1700 
1701 template<uint NAXES,typename SUBCLASS>
1703 {
1704  float u = SYSatan(uvw[1], uvw[0]) / (float)(2*M_PI);
1705  if (u < 0)
1706  u += 1;
1707  if (NAXES == 3)
1708  {
1709  float v = SYSacos(uvw[2]) / (float)M_PI;
1710  uvw[0] = u;
1711  uvw[1] = v;
1712  uvw[2] = 0;
1713  }
1714  else
1715  {
1716  UT_ASSERT(NAXES==2);
1717  uvw[0] = u;
1718  uvw[1] = 0;
1719  }
1720 }
1721 
1722 template<uint NAXES,typename SUBCLASS>
1723 template<GA_AttributeOwner owner,typename T,typename DEST_T>
1724 bool BVHBase<NAXES,SUBCLASS>::getAttribute(const CommonHitInfo &hit_info, const GA_ROHandleT<T> &attrib, const GEO_Detail &detail, DEST_T &value) const noexcept
1725 {
1726  UT_ASSERT(owner == attrib->getOwner());
1727 
1728  if (owner == GA_ATTRIB_DETAIL)
1729  {
1730  value = attrib.get(GA_DETAIL_OFFSET);
1731  return true;
1732  }
1733 
1734  exint index = hit_info.myItemIndex;
1735  if (!SUBCLASS::theHasPrimitives || index < numPoints())
1736  {
1737  if (owner != GA_ATTRIB_POINT)
1738  return false;
1739 
1740  GA_Offset ptoff = myPoints(index);
1741  value = attrib.get(ptoff);
1742  return true;
1743  }
1744  return subclass()->template primAttribute<owner,T,DEST_T>(hit_info, attrib, detail, value);
1745 }
1746 
1747 } // GEO namespace
1748 
1749 #undef GEO_BVH_INTERLEAVED
#define SYSmax(a, b)
Definition: SYS_Math.h:1582
T & last()
Definition: UT_Array.h:823
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:1662
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:379
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:201
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:702
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:1584
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:158
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:653
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:159
GA_Size GA_Offset
Definition: GA_Types.h:646
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:1724
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
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:1642
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:137
#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
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:1702
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:694
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:849
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:156
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:691
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:1583
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:309
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:721
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
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:657