HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_BVH.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  * Bounding Volume Hierarchy (BVH) implementation.
27  * To call functions not implemented here, also include UT_BVHImpl.h
28  */
29 
30 #pragma once
31 
32 #ifndef __HDK_UT_BVH_h__
33 #define __HDK_UT_BVH_h__
34 
35 #include <UT/UT_FixedVector.h>
36 #include <UT/UT_SmallArray.h>
37 #include <UT/UT_UniquePtr.h>
38 #include <SYS/SYS_Inline.h>
39 #include <SYS/SYS_StaticAssert.h>
40 #include <SYS/SYS_Types.h>
41 #include <SYS/SYS_TypeTraits.h>
42 #include <limits>
43 
44 template<typename T> class UT_Array;
45 class v4uf;
46 class v4uu;
47 
48 namespace HDK_Sample {
49 
50 namespace UT {
51 
52 template<typename T,uint NAXES>
53 struct Box {
54  T vals[NAXES][2];
55 
56  SYS_FORCE_INLINE Box() noexcept = default;
57  SYS_FORCE_INLINE constexpr Box(const Box &other) noexcept = default;
58  SYS_FORCE_INLINE constexpr Box(Box &&other) noexcept = default;
59  SYS_FORCE_INLINE Box& operator=(const Box &other) noexcept = default;
60  SYS_FORCE_INLINE Box& operator=(Box &&other) noexcept = default;
61 
62  template<typename S>
63  SYS_FORCE_INLINE Box(const Box<S,NAXES>& other) noexcept {
64  SYS_STATIC_ASSERT_MSG((SYSisPOD<Box<T,NAXES>>()) || !SYSisPOD<T>(),
65  "UT::Box should be POD, for better performance in UT_Array, etc.");
66 
67  for (uint axis = 0; axis < NAXES; ++axis) {
68  vals[axis][0] = T(other.vals[axis][0]);
69  vals[axis][1] = T(other.vals[axis][1]);
70  }
71  }
72 
73  template< typename TS >
74  SYS_FORCE_INLINE explicit Box(const TS& pt) noexcept
75  {
76  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
77 
78  for (uint axis = 0; axis < NAXES; ++axis) {
79  vals[axis][0] = pt[axis];
80  vals[axis][1] = pt[axis];
81  }
82  }
83 
84  template<typename S>
85  SYS_FORCE_INLINE Box& operator=(const Box<S,NAXES>& other) noexcept {
86  for (uint axis = 0; axis < NAXES; ++axis) {
87  vals[axis][0] = T(other.vals[axis][0]);
88  vals[axis][1] = T(other.vals[axis][1]);
89  }
90  return *this;
91  }
92 
93  SYS_FORCE_INLINE const T* operator[](const size_t axis) const noexcept {
94  UT_ASSERT_P(axis < NAXES);
95  return vals[axis];
96  }
97  SYS_FORCE_INLINE T* operator[](const size_t axis) noexcept {
98  UT_ASSERT_P(axis < NAXES);
99  return vals[axis];
100  }
101 
102  SYS_FORCE_INLINE void initBounds() noexcept {
103  for (uint axis = 0; axis < NAXES; ++axis) {
104  vals[axis][0] = std::numeric_limits<T>::max();
105  vals[axis][1] = -std::numeric_limits<T>::max();
106  }
107  }
108  /// Copy the source box.
109  /// NOTE: This is so that in templated code that may have a Box or a
110  /// UT_FixedVector, it can call initBounds and still work.
111  SYS_FORCE_INLINE void initBounds(const Box<T,NAXES>& src) noexcept {
112  for (uint axis = 0; axis < NAXES; ++axis) {
113  vals[axis][0] = src.vals[axis][0];
114  vals[axis][1] = src.vals[axis][1];
115  }
116  }
117  /// Initialize with the union of the source boxes.
118  /// NOTE: This is so that in templated code that may have Box's or a
119  /// UT_FixedVector's, it can call initBounds and still work.
120  SYS_FORCE_INLINE void initBoundsUnordered(const Box<T,NAXES>& src0, const Box<T,NAXES>& src1) noexcept {
121  for (uint axis = 0; axis < NAXES; ++axis) {
122  vals[axis][0] = SYSmin(src0.vals[axis][0], src1.vals[axis][0]);
123  vals[axis][1] = SYSmax(src0.vals[axis][1], src1.vals[axis][1]);
124  }
125  }
126  SYS_FORCE_INLINE void combine(const Box<T,NAXES>& src) noexcept {
127  for (uint axis = 0; axis < NAXES; ++axis) {
128  T& minv = vals[axis][0];
129  T& maxv = vals[axis][1];
130  const T curminv = src.vals[axis][0];
131  const T curmaxv = src.vals[axis][1];
132  minv = (minv < curminv) ? minv : curminv;
133  maxv = (maxv > curmaxv) ? maxv : curmaxv;
134  }
135  }
136 
137  template< typename TS >
139  void initBounds(const TS& pt) noexcept
140  {
141  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
142 
143  for (uint axis = 0; axis < NAXES; ++axis) {
144  vals[axis][0] = pt[axis];
145  vals[axis][1] = pt[axis];
146  }
147  }
148 
149  template< typename TS >
152  const TS& min,
153  const TS& max
154  ) noexcept
155  {
156  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
157 
158  for (uint axis = 0; axis < NAXES; ++axis) {
159  vals[axis][0] = min[axis];
160  vals[axis][1] = max[axis];
161  }
162  }
163 
164  template< typename TS >
166  void initBoundsUnordered(const TS& p0, const TS& p1) noexcept
167  {
168  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
169 
170  for (uint axis = 0; axis < NAXES; ++axis) {
171  vals[axis][0] = SYSmin(p0[axis], p1[axis]);
172  vals[axis][1] = SYSmax(p0[axis], p1[axis]);
173  }
174  }
175 
176  template< typename TS >
178  void enlargeBounds(const TS& pt) noexcept
179  {
180  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
181 
182  for (uint axis = 0; axis < NAXES; ++axis) {
183  vals[axis][0] = SYSmin(vals[axis][0], pt[axis]);
184  vals[axis][1] = SYSmax(vals[axis][1], pt[axis]);
185  }
186  }
187 
188  template< typename TS >
189  SYS_FORCE_INLINE void combine(const TS& pt) noexcept
190  {
191  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, NAXES > );
192 
193  enlargeBounds(pt);
194  }
195 
199  for (uint axis = 0; axis < NAXES; ++axis) {
200  v[axis] = vals[axis][0];
201  }
202  return v;
203  }
204 
208  for (uint axis = 0; axis < NAXES; ++axis) {
209  v[axis] = vals[axis][1];
210  }
211  return v;
212  }
213 
214  T diameter2() const noexcept {
215  T diff = (vals[0][1]-vals[0][0]);
216  T sum = diff*diff;
217  for (uint axis = 1; axis < NAXES; ++axis) {
218  diff = (vals[axis][1]-vals[axis][0]);
219  sum += diff*diff;
220  }
221  return sum;
222  }
223  T volume() const noexcept {
224  T product = (vals[0][1]-vals[0][0]);
225  for (uint axis = 1; axis < NAXES; ++axis) {
226  product *= (vals[axis][1]-vals[axis][0]);
227  }
228  return product;
229  }
230  T half_surface_area() const noexcept {
231  if (NAXES==1) {
232  // NOTE: Although this should technically be 1,
233  // that doesn't make any sense as a heuristic,
234  // so we fall back to the "volume" of this box.
235  return (vals[0][1]-vals[0][0]);
236  }
237  if (NAXES==2) {
238  const T d0 = (vals[0][1]-vals[0][0]);
239  const T d1 = (vals[1][1]-vals[1][0]);
240  return d0 + d1;
241  }
242  if (NAXES==3) {
243  const T d0 = (vals[0][1]-vals[0][0]);
244  const T d1 = (vals[1][1]-vals[1][0]);
245  const T d2 = (vals[2][1]-vals[2][0]);
246  return d0*d1 + d1*d2 + d2*d0;
247  }
248  if (NAXES==4) {
249  const T d0 = (vals[0][1]-vals[0][0]);
250  const T d1 = (vals[1][1]-vals[1][0]);
251  const T d2 = (vals[2][1]-vals[2][0]);
252  const T d3 = (vals[3][1]-vals[3][0]);
253  // This is just d0d1d2 + d1d2d3 + d2d3d0 + d3d0d1 refactored.
254  const T d0d1 = d0*d1;
255  const T d2d3 = d2*d3;
256  return d0d1*(d2+d3) + d2d3*(d0+d1);
257  }
258 
259  T sum = 0;
260  for (uint skipped_axis = 0; skipped_axis < NAXES; ++skipped_axis) {
261  T product = 1;
262  for (uint axis = 0; axis < NAXES; ++axis) {
263  if (axis != skipped_axis) {
264  product *= (vals[axis][1]-vals[axis][0]);
265  }
266  }
267  sum += product;
268  }
269  return sum;
270  }
271  T axis_sum() const noexcept {
272  T sum = (vals[0][1]-vals[0][0]);
273  for (uint axis = 1; axis < NAXES; ++axis) {
274  sum += (vals[axis][1]-vals[axis][0]);
275  }
276  return sum;
277  }
279  T &box_tmin,
280  T &box_tmax,
281  const UT_FixedVector<uint,NAXES> &signs,
282  const UT_FixedVector<T,NAXES> &origin,
283  const UT_FixedVector<T,NAXES> &inverse_direction
284  ) const noexcept {
285  for (int axis = 0; axis < NAXES; ++axis)
286  {
287  uint sign = signs[axis];
288  T t1 = (vals[axis][sign] - origin[axis]) * inverse_direction[axis];
289  T t2 = (vals[axis][sign^1] - origin[axis]) * inverse_direction[axis];
290  box_tmin = SYSmax(t1, box_tmin);
291  box_tmax = SYSmin(t2, box_tmax);
292  }
293  }
294  SYS_FORCE_INLINE void intersect(const Box& other, Box& dest) const noexcept {
295  for (int axis = 0; axis < NAXES; ++axis)
296  {
297  dest.vals[axis][0] = SYSmax(vals[axis][0], other.vals[axis][0]);
298  dest.vals[axis][1] = SYSmin(vals[axis][1], other.vals[axis][1]);
299  }
300  }
302  const UT_FixedVector<T,NAXES> &p
303  ) const noexcept {
304  T diff = SYSmax(SYSmax(vals[0][0]-p[0], p[0]-vals[0][1]), T(0.0f));
305  T d2 = diff*diff;
306  for (int axis = 1; axis < NAXES; ++axis)
307  {
308  diff = SYSmax(SYSmax(vals[axis][0]-p[axis], p[axis]-vals[axis][1]), T(0.0f));
309  d2 += diff*diff;
310  }
311  return d2;
312  }
314  const UT_FixedVector<T,NAXES> &p
315  ) const noexcept {
316  T diff = SYSmax(p[0]-vals[0][0], vals[0][1]-p[0]);
317  T d2 = diff*diff;
318  for (int axis = 1; axis < NAXES; ++axis)
319  {
320  diff = SYSmax(p[axis]-vals[axis][0], vals[axis][1]-p[axis]);
321  d2 += diff*diff;
322  }
323  return d2;
324  }
325 };
326 
327 /// Used by BVH::init to specify the heuristic to use for choosing between different box splits.
328 /// I tried putting this inside the BVH class, but I had difficulty getting it to compile.
329 enum class BVH_Heuristic {
330  /// Tries to minimize the sum of axis lengths of the boxes.
331  /// This is useful for applications where the probability of a box being applicable to a
332  /// query is proportional to the "length", e.g. the probability of a random infinite plane
333  /// intersecting the box.
335 
336  /// Tries to minimize the "surface area" of the boxes.
337  /// In 3D, uses the surface area; in 2D, uses the perimeter; in 1D, uses the axis length.
338  /// This is what most applications, e.g. ray tracing, should use, particularly when the
339  /// probability of a box being applicable to a query is proportional to the surface "area",
340  /// e.g. the probability of a random ray hitting the box.
341  ///
342  /// NOTE: USE THIS ONE IF YOU ARE UNSURE!
343  BOX_AREA,
344 
345  /// Tries to minimize the "volume" of the boxes.
346  /// Uses the product of all axis lengths as a heuristic, (volume in 3D, area in 2D, length in 1D).
347  /// This is useful for applications where the probability of a box being applicable to a
348  /// query is proportional to the "volume", e.g. the probability of a random point being inside the box.
349  BOX_VOLUME,
350 
351  /// Tries to minimize the "radii" of the boxes (i.e. the distance from the centre to a corner).
352  /// This is useful for applications where the probability of a box being applicable to a
353  /// query is proportional to the distance to the box centre, e.g. the probability of a random
354  /// infinite plane being within the "radius" of the centre.
355  BOX_RADIUS,
356 
357  /// Tries to minimize the squared "radii" of the boxes (i.e. the squared distance from the centre to a corner).
358  /// This is useful for applications where the probability of a box being applicable to a
359  /// query is proportional to the squared distance to the box centre, e.g. the probability of a random
360  /// ray passing within the "radius" of the centre.
361  BOX_RADIUS2,
362 
363  /// Tries to minimize the cubed "radii" of the boxes (i.e. the cubed distance from the centre to a corner).
364  /// This is useful for applications where the probability of a box being applicable to a
365  /// query is proportional to the cubed distance to the box centre, e.g. the probability of a random
366  /// point being within the "radius" of the centre.
367  BOX_RADIUS3,
368 
369  /// Tries to minimize the depth of the tree by primarily splitting at the median of the max axis.
370  /// It may fall back to minimizing the area, but the tree depth should be unaffected.
371  ///
372  /// FIXME: This is not fully implemented yet.
374 };
375 
376 template<uint N>
377 class BVH {
378 public:
379  using INT_TYPE = uint;
380  struct Node {
382 
383  static constexpr INT_TYPE theN = N;
384  static constexpr INT_TYPE EMPTY = INT_TYPE(-1);
385  static constexpr INT_TYPE INTERNAL_BIT = (INT_TYPE(1)<<(sizeof(INT_TYPE)*8 - 1));
386  SYS_FORCE_INLINE static INT_TYPE markInternal(INT_TYPE internal_node_num) noexcept {
387  return internal_node_num | INTERNAL_BIT;
388  }
389  SYS_FORCE_INLINE static bool isInternal(INT_TYPE node_int) noexcept {
390  return (node_int & INTERNAL_BIT) != 0;
391  }
392  SYS_FORCE_INLINE static INT_TYPE getInternalNum(INT_TYPE node_int) noexcept {
393  return node_int & ~INTERNAL_BIT;
394  }
395  };
396 private:
397  struct FreeDeleter {
398  SYS_FORCE_INLINE void operator()(Node* p) const {
399  if (p) {
400  // The pointer was allocated with malloc by UT_Array,
401  // so it must be freed with free.
402  free(p);
403  }
404  }
405  };
406 
408  INT_TYPE myNumNodes;
409 public:
410  SYS_FORCE_INLINE BVH() noexcept : myRoot(nullptr), myNumNodes(0) {}
411 
412  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE=INT_TYPE>
413  void init(const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept;
414 
415  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE=INT_TYPE>
416  void init(Box<T,NAXES> axes_minmax, const BOX_TYPE* boxes, INT_TYPE nboxes, SRC_INT_TYPE* indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept;
417 
420  {
421  return myNumNodes;
422  }
424  const Node *getNodes() const noexcept
425  {
426  return myRoot.get();
427  }
428 
430  void clear() noexcept {
431  myRoot.reset();
432  myNumNodes = 0;
433  }
434 
435  /// For each node, this effectively does:
436  /// LOCAL_DATA local_data[MAX_ORDER];
437  /// bool descend = functors.pre(nodei, parent_data);
438  /// if (!descend)
439  /// return;
440  /// for each child {
441  /// if (isitem(child))
442  /// functors.item(getitemi(child), nodei, local_data[child]);
443  /// else if (isnode(child))
444  /// recurse(getnodei(child), local_data);
445  /// }
446  /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data);
447  template<typename LOCAL_DATA,typename FUNCTORS>
448  void traverse(
449  FUNCTORS &functors,
450  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
451 
452  /// This acts like the traverse function, except if the number of nodes in two subtrees
453  /// of a node contain at least parallel_threshold nodes, they may be executed in parallel.
454  /// If parallel_threshold is 0, even item_functor may be executed on items in parallel.
455  /// NOTE: Make sure that your functors don't depend on the order that they're executed in,
456  /// e.g. don't add values from sibling nodes together except in post functor,
457  /// else they might have nondeterministic roundoff or miss some values entirely.
458  template<typename LOCAL_DATA,typename FUNCTORS>
459  void traverseParallel(
460  INT_TYPE parallel_threshold,
461  FUNCTORS &functors,
462  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
463 
464  /// For each node, this effectively does:
465  /// LOCAL_DATA local_data[MAX_ORDER];
466  /// uint descend = functors.pre(nodei, parent_data);
467  /// if (!descend)
468  /// return;
469  /// for each child {
470  /// if (!(descend & (1<<child)))
471  /// continue;
472  /// if (isitem(child))
473  /// functors.item(getitemi(child), nodei, local_data[child]);
474  /// else if (isnode(child))
475  /// recurse(getnodei(child), local_data);
476  /// }
477  /// functors.post(nodei, parent_nodei, data_for_parent, num_children, local_data);
478  template<typename LOCAL_DATA,typename FUNCTORS>
479  void traverseVector(
480  FUNCTORS &functors,
481  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
482 
483  /// Prints a text representation of the tree to stdout.
484  void debugDump() const;
485 
486  template<typename SRC_INT_TYPE>
487  static void createTrivialIndices(SRC_INT_TYPE* indices, const INT_TYPE n) noexcept;
488 
489 private:
490  template<typename LOCAL_DATA,typename FUNCTORS>
491  void traverseHelper(
492  INT_TYPE nodei,
493  INT_TYPE parent_nodei,
494  FUNCTORS &functors,
495  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
496 
497  template<typename LOCAL_DATA,typename FUNCTORS>
498  void traverseParallelHelper(
499  INT_TYPE nodei,
500  INT_TYPE parent_nodei,
501  INT_TYPE parallel_threshold,
502  INT_TYPE next_node_id,
503  FUNCTORS &functors,
504  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
505 
506  template<typename LOCAL_DATA,typename FUNCTORS>
507  void traverseVectorHelper(
508  INT_TYPE nodei,
509  INT_TYPE parent_nodei,
510  FUNCTORS &functors,
511  LOCAL_DATA *data_for_parent=nullptr) const noexcept;
512 
513  template<typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
514  static void computeFullBoundingBox(Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, const INT_TYPE nboxes, SRC_INT_TYPE* indices) noexcept;
515 
516  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
517  static void initNode(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes) noexcept;
518 
519  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
520  static void initNodeReorder(UT_Array<Node>& nodes, Node &node, const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const INT_TYPE nboxes, const INT_TYPE indices_offset, const INT_TYPE max_items_per_leaf) noexcept;
521 
522  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
523  static void multiSplit(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE* sub_indices[N+1], Box<T,NAXES> sub_boxes[N]) noexcept;
524 
525  template<BVH_Heuristic H,typename T,uint NAXES,typename BOX_TYPE,typename SRC_INT_TYPE>
526  static void split(const Box<T,NAXES>& axes_minmax, const BOX_TYPE* boxes, SRC_INT_TYPE* indices, INT_TYPE nboxes, SRC_INT_TYPE*& split_indices, Box<T,NAXES>* split_boxes) noexcept;
527 
528  template<INT_TYPE PARALLEL_THRESHOLD, typename SRC_INT_TYPE>
529  static void adjustParallelChildNodes(INT_TYPE nparallel, UT_Array<Node>& nodes, Node& node, UT_Array<Node>* parallel_nodes, SRC_INT_TYPE* sub_indices) noexcept;
530 
531  template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
532  static void nthElement(const BOX_TYPE* boxes, SRC_INT_TYPE* indices, const SRC_INT_TYPE* indices_end, const uint axis, SRC_INT_TYPE*const nth) noexcept;
533 
534  template<typename T,typename BOX_TYPE,typename SRC_INT_TYPE>
535  static void partitionByCentre(const BOX_TYPE* boxes, SRC_INT_TYPE*const indices, const SRC_INT_TYPE*const indices_end, const uint axis, const T pivotx2, SRC_INT_TYPE*& ppivot_start, SRC_INT_TYPE*& ppivot_end) noexcept;
536 
537  /// An overestimate of the number of nodes needed.
538  /// At worst, we could have only 2 children in every leaf, and
539  /// then above that, we have a geometric series with r=1/N and a=(sub_nboxes/2)/N
540  /// The true worst case might be a little worst than this, but
541  /// it's probably fairly unlikely.
542  SYS_FORCE_INLINE static INT_TYPE nodeEstimate(const INT_TYPE nboxes) noexcept {
543  return nboxes/2 + nboxes/(2*(N-1));
544  }
545 
546  template<BVH_Heuristic H,typename T, uint NAXES>
547  SYS_FORCE_INLINE static T unweightedHeuristic(const Box<T, NAXES>& box) noexcept {
549  return box.axis_sum();
550  }
551  if (H == BVH_Heuristic::BOX_AREA) {
552  return box.half_surface_area();
553  }
554  if (H == BVH_Heuristic::BOX_VOLUME) {
555  return box.volume();
556  }
557  if (H == BVH_Heuristic::BOX_RADIUS) {
558  T diameter2 = box.diameter2();
559  return SYSsqrt(diameter2);
560  }
561  if (H == BVH_Heuristic::BOX_RADIUS2) {
562  return box.diameter2();
563  }
564  if (H == BVH_Heuristic::BOX_RADIUS3) {
565  T diameter2 = box.diameter2();
566  return diameter2*SYSsqrt(diameter2);
567  }
568  UT_ASSERT_MSG(0, "BVH_Heuristic::MEDIAN_MAX_AXIS should be handled separately by caller!");
569  return T(1);
570  }
571 
572  /// 16 equal-length spans (15 evenly-spaced splits) should be enough for a decent heuristic
573  static constexpr INT_TYPE NSPANS = 16;
574  static constexpr INT_TYPE NSPLITS = NSPANS-1;
575 
576  /// At least 1/16 of all boxes must be on each side, else we could end up with a very deep tree
577  static constexpr INT_TYPE MIN_FRACTION = 16;
578 };
579 
580 } // UT namespace
581 
582 template<uint N>
584 
585 } // End HDK_Sample namespace
586 #endif
SYS_FORCE_INLINE void initBounds(const TS &min, const TS &max) noexcept
Definition: UT_BVH.h:151
#define SYSmax(a, b)
Definition: SYS_Math.h:1538
SYS_FORCE_INLINE UT_FixedVector< T, NAXES > getMax() const noexcept
Definition: UT_BVH.h:206
void traverseParallel(INT_TYPE parallel_threshold, FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
Definition: UT_BVHImpl.h:392
#define SYS_STATIC_ASSERT(expr)
GLsizei GLenum const void * indices
Definition: glcorearb.h:406
static SYS_FORCE_INLINE INT_TYPE markInternal(INT_TYPE internal_node_num) noexcept
Definition: UT_BVH.h:386
SYS_FORCE_INLINE void initBounds(const TS &pt) noexcept
Definition: UT_BVH.h:139
#define SYS_STATIC_ASSERT_MSG(expr, msg)
SYS_FORCE_INLINE void initBounds() noexcept
Definition: UT_BVH.h:102
Definition: Node.h:52
T half_surface_area() const noexcept
Definition: UT_BVH.h:230
const GLdouble * v
Definition: glcorearb.h:837
SYS_FORCE_INLINE T * operator[](const size_t axis) noexcept
Definition: UT_BVH.h:97
SYS_FORCE_INLINE void initBounds(const Box< T, NAXES > &src) noexcept
Definition: UT_BVH.h:111
static void createTrivialIndices(SRC_INT_TYPE *indices, const INT_TYPE n) noexcept
Definition: UT_BVHImpl.h:562
void debugDump() const
Prints a text representation of the tree to stdout.
SYS_FORCE_INLINE BVH() noexcept
Definition: UT_BVH.h:410
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
SYS_FORCE_INLINE Box() noexcept=default
SYS_FORCE_INLINE Box & operator=(const Box< S, NAXES > &other) noexcept
Definition: UT_BVH.h:85
SYS_FORCE_INLINE INT_TYPE getNumNodes() const noexcept
Definition: UT_BVH.h:419
void traverse(FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
Definition: UT_BVHImpl.h:349
SYS_FORCE_INLINE const Node * getNodes() const noexcept
Definition: UT_BVH.h:424
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
T diameter2() const noexcept
Definition: UT_BVH.h:214
SYS_FORCE_INLINE void combine(const TS &pt) noexcept
Definition: UT_BVH.h:189
#define UT_ASSERT_MSG(ZZ,...)
Definition: UT_Assert.h:159
GLdouble n
Definition: glcorearb.h:2008
GLfloat f
Definition: glcorearb.h:1926
T axis_sum() const noexcept
Definition: UT_BVH.h:271
SYS_FORCE_INLINE T maxDistance2(const UT_FixedVector< T, NAXES > &p) const noexcept
Definition: UT_BVH.h:313
SYS_FORCE_INLINE T minDistance2(const UT_FixedVector< T, NAXES > &p) const noexcept
Definition: UT_BVH.h:301
Definition: VM_SIMD.h:48
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
SYS_FORCE_INLINE void intersect(const Box &other, Box &dest) const noexcept
Definition: UT_BVH.h:294
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
Definition: VM_SIMD.h:188
SYS_FORCE_INLINE void initBoundsUnordered(const Box< T, NAXES > &src0, const Box< T, NAXES > &src1) noexcept
Definition: UT_BVH.h:120
static constexpr INT_TYPE EMPTY
Definition: UT_BVH.h:384
SYS_FORCE_INLINE const T * operator[](const size_t axis) const noexcept
Definition: UT_BVH.h:93
STATIC_INLINE uint64_t H(uint64_t x, uint64_t y, uint64_t mul, int r)
Definition: farmhash.h:701
SYS_FORCE_INLINE Box(const TS &pt) noexcept
Definition: UT_BVH.h:74
IMATH_HOSTDEVICE constexpr int sign(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:33
void init(const BOX_TYPE *boxes, const INT_TYPE nboxes, SRC_INT_TYPE *indices=nullptr, bool reorder_indices=false, INT_TYPE max_items_per_leaf=1) noexcept
Definition: UT_BVHImpl.h:292
SYS_FORCE_INLINE void initBoundsUnordered(const TS &p0, const TS &p1) noexcept
Definition: UT_BVH.h:166
SYS_FORCE_INLINE void clear() noexcept
Definition: UT_BVH.h:430
static constexpr INT_TYPE theN
Definition: UT_BVH.h:383
SYS_FORCE_INLINE UT_FixedVector< T, NAXES > getMin() const noexcept
Definition: UT_BVH.h:197
SYS_FORCE_INLINE void enlargeBounds(const TS &pt) noexcept
Definition: UT_BVH.h:178
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GA_API const UT_StringHolder N
void traverseVector(FUNCTORS &functors, LOCAL_DATA *data_for_parent=nullptr) const noexcept
Definition: UT_BVHImpl.h:516
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:278
Definition: ImathBox.h:37
#define const
Definition: zconf.h:214
static SYS_FORCE_INLINE bool isInternal(INT_TYPE node_int) noexcept
Definition: UT_BVH.h:389
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
T volume() const noexcept
Definition: UT_BVH.h:223
SYS_FORCE_INLINE void combine(const Box< T, NAXES > &src) noexcept
Definition: UT_BVH.h:126
unsigned int uint
Definition: SYS_Types.h:45
static SYS_FORCE_INLINE INT_TYPE getInternalNum(INT_TYPE node_int) noexcept
Definition: UT_BVH.h:392
T vals[NAXES][2]
Definition: UT_BVH.h:54
GLenum src
Definition: glcorearb.h:1793
static constexpr INT_TYPE INTERNAL_BIT
Definition: UT_BVH.h:385