Fermat
bvh_sah_builder_inline.h
1 /*
2  * Copyright (c) 2010-2018, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 namespace cugar {
29 
30 //
31 // IndexSortPredicate implementation.
32 //
33 
34 // Predicate to sort indices based on their entity's AABB center.
36 {
37 public:
38  IndexSortPredicate(const std::vector<Entity>& entities, int dim)
39  : m_entities( entities ),
40  m_dim( dim )
41  {}
42 
43  bool operator() (int lhs, int rhs) const
44  {
45  const Bbox3f& left = m_entities[lhs].m_bbox;
46  const Bbox3f& right = m_entities[rhs].m_bbox;
47  const float leftval = left.m_min[m_dim] + left.m_max[m_dim];
48  const float rightval = right.m_min[m_dim] + right.m_max[m_dim];
49  return leftval < rightval;
50  }
51 
52 private:
53  const std::vector<Entity>& m_entities;
54  int m_dim;
55 };
56 
57 inline void Bvh_sah_builder::build(
58  const uint32 n_entities,
59  bvh_type* bvh,
60  Stats* stats)
61 {
62  std::vector<bvh_node_type>& nodes = bvh->m_nodes;
63 
64  // initialize tag bits
65  m_tag_bits.resize( n_entities, false );
66 
67  // Initialize indices.
68  m_tmpInt.resize( n_entities );
69 
70  m_indices[0].resize( n_entities );
71  for(uint32 i = 0; i < n_entities; ++i)
72  m_indices[0][i] = static_cast<int>( i );
73 
74  for(int dim = 1; dim < 3; ++dim)
75  m_indices[dim] = m_indices[0];
76 
77  // Sort index arrays by their dimension.
78  IndexSortPredicate pred_x( m_entities, 0 );
79  IndexSortPredicate pred_y( m_entities, 1 );
80  IndexSortPredicate pred_z( m_entities, 2 );
81  std::sort( m_indices[0].begin(), m_indices[0].end(), pred_x );
82  std::sort( m_indices[1].begin(), m_indices[1].end(), pred_y );
83  std::sort( m_indices[2].begin(), m_indices[2].end(), pred_z );
84 
85  // create root
86  Bbox3f root_bbox;
87  compute_bbox( 0u, n_entities, root_bbox );
88 
89  Node_stack node_stack;
90  {
91  Node node;
92  node.m_bbox = root_bbox;
93  node.m_begin = 0u;
94  node.m_end = n_entities;
95  node.m_depth = 0u;
96  node.m_node = 0u;
97 
98  node_stack.push( node );
99  }
100 
101  if (stats)
102  stats->m_max_depth = 0u;
103 
104  bvh_node_type root = bvh_node_type( Bvh_node::kInternal, 0u, uint32(-1) );
105  nodes.erase( nodes.begin(), nodes.end() );
106  nodes.push_back( root );
107  bvh->m_bboxes.resize( 1u );
108  bvh->m_bboxes[0] = root_bbox;
109 
110  while (node_stack.empty() == false)
111  {
112  const Node node = node_stack.top();
113  node_stack.pop();
114 
115  const uint32 node_index = node.m_node;
116  const bbox_type bbox = node.m_bbox;
117 
118  // set the node bbox
119  bvh->m_bboxes[ node_index ] = bbox;
120 
121  if (stats)
122  stats->m_max_depth = std::max( stats->m_max_depth, node.m_depth );
123 
124  if (node.m_end - node.m_begin <= m_max_leaf_size)
125  {
126  //
127  // Make a leaf node
128  //
129  bvh_node_type& bvh_node = nodes[ node_index ];
130  bvh_node = bvh_node_type( node.m_begin, node.m_end );
131  }
132  else
133  {
134  //
135  // Make a split node
136  //
137 
138  uint32 middle;
139  bbox_type l_bb, r_bb;
140 
141  if (find_best_split( node, middle, l_bb, r_bb ) == false)
142  {
143  if (m_force_splitting)
144  {
145  middle = (node.m_begin + node.m_end) / 2;
146  compute_bbox( node.m_begin, middle, l_bb );
147  compute_bbox( middle, node.m_end, r_bb );
148  }
149  else
150  {
151  // unsuccessful split: make a leaf node
152  bvh_node_type& bvh_node = nodes[ node_index ];
153  bvh_node = bvh_node_type( node.m_begin, node.m_end );
154  continue;
155  }
156  }
157 
158  // alloc space for children
159  const uint32 left_node_index = uint32( nodes.size() );
160  nodes.resize( left_node_index + 2 );
161  bvh->m_bboxes.resize( left_node_index + 2 );
162 
163  bvh_node_type& bvh_node = nodes[ node_index ];
164  bvh_node = bvh_node_type( left_node_index );
165 
166  // push left and right children in processing queue
167  Node right_node;
168  right_node.m_bbox = r_bb;
169  right_node.m_begin = middle;
170  right_node.m_end = node.m_end;
171  right_node.m_depth = node.m_depth + 1u;
172  right_node.m_node = left_node_index + 1u;
173  node_stack.push( right_node );
174 
175  Node left_node;
176  left_node.m_bbox = l_bb;
177  left_node.m_begin = node.m_begin;
178  left_node.m_end = middle;
179  left_node.m_depth = node.m_depth + 1u;
180  left_node.m_node = left_node_index;
181  node_stack.push( left_node );
182  }
183  }
184 }
185 
186 template <typename Iterator>
188  const Iterator begin,
189  const Iterator end,
190  bvh_type* bvh,
191  Stats* stats)
192 {
193  const uint32 n_entities = uint32( end - begin );
194 
195  m_entities.resize( n_entities );
196  uint32 i = 0;
197  for (Iterator it = begin; it != end; ++it)
198  {
199  m_entities[i].m_bbox = *it;
200  m_entities[i].m_index = i;
201  m_entities[i].m_cost = 1.0f;
202 
203  i++;
204  }
205 
206  build( n_entities, bvh, stats );
207 }
208 // build
209 //
210 // Iterator is supposed to dereference to a Bbox3f
211 //
212 // \param begin first point
213 // \param end last point
214 // \param bvh output bvh
215 template <typename Iterator, typename CostIterator>
217  Iterator begin,
218  Iterator end,
219  CostIterator cost_begin,
220  bvh_type* bvh,
221  Stats* stats)
222 {
223  const uint32 n_entities = uint32( end - begin );
224 
225  m_entities.resize( n_entities );
226  uint32 i = 0;
227  for (Iterator it = begin; it != end; ++it)
228  {
229  m_entities[i].m_bbox = *it;
230  m_entities[i].m_index = i;
231  m_entities[i].m_cost = cost_begin[i];
232 
233  i++;
234  }
235 
236  build( n_entities, bvh, stats );
237 }
238 
239 // Predicate to sort indices based on their entity's AABB center.
241 {
242 public:
243  Predicate(int dim) : m_dim( dim ) {}
244 
245  bool operator() (const Entity& lhs, const Entity& rhs) const
246  {
247  const float leftval = lhs.m_bbox[0][m_dim] + lhs.m_bbox[1][m_dim];
248  const float rightval = rhs.m_bbox[0][m_dim] + rhs.m_bbox[1][m_dim];
249 
250  if (leftval == rightval)
251  return lhs.m_index < rhs.m_index;
252 
253  return leftval < rightval;
254  }
255 
256 private:
257  int m_dim;
258 };
259 
260 inline float Bvh_sah_builder::area(const Bbox3f& bbox)
261 {
262  const Vector3f edge = bbox[1] - bbox[0];
263  return edge[0] * edge[1] + edge[2] * (edge[0] + edge[1]);
264 }
265 
266 inline bool Bvh_sah_builder::find_largest_axis_split(
267  const Node& node,
268  uint32& pivot,
269  bbox_type& left_bb,
270  bbox_type& right_bb)
271 {
272  const uint32 begin = node.m_begin;
273  const uint32 end = node.m_end;
274  const uint32 n_entities = end - begin;
275  if (m_bboxes.size() < n_entities+1)
276  m_bboxes.resize( n_entities+1 );
277  if (m_costs.size() < n_entities+1)
278  m_costs.resize( n_entities+1 );
279 
280  float min_cost = std::numeric_limits<float>::max();
281  int min_dim = -1;
282 
283  const vector_type edge = node.m_bbox[1] - node.m_bbox[0];
284  const int dim = max_element( edge );
285 
286  Predicate predicate( dim );
287 
288  m_bboxes[0] = bbox_type();
289  m_costs[0] = 0.0f;
290 
291  std::vector<int>& indices = m_indices[dim];
292 
293  // Accumulate right hand side bboxes.
294  for(uint32 i = 1; i <= n_entities; ++i)
295  m_bboxes[i] = bbox_type( m_bboxes[i-1], m_entities[ indices[ end - i ] ].m_bbox );
296 
297  for(uint32 i = 1; i <= n_entities; ++i)
298  m_costs[i] = m_costs[i-1] + m_entities[ indices[ end - i ] ].m_cost;
299 
300  // Loop over possible splits and find the cheapest one.
301  bbox_type lbb, rbb;
302  float lc = 0.0f, rc;
303 
304  for(uint32 num_left = 1; num_left < n_entities; ++num_left)
305  {
306  const int num_right = n_entities - num_left;
307 
308  rbb = m_bboxes[num_right];
309  lbb.insert( m_entities[ indices[ begin + num_left - 1 ] ].m_bbox );
310 
311  rc = m_costs[num_right];
312  lc += m_entities[ indices[ begin + num_left - 1 ] ].m_cost;
313 
314  if (m_force_alignment && (num_left % m_max_leaf_size != 0))
315  continue;
316 
317  const float sa_left = area( lbb );
318  const float sa_right = area( rbb );
319 
320  const float cost = sa_left*lc + sa_right*rc;
321 
322  if(cost < min_cost)
323  {
324  min_cost = cost;
325  min_dim = dim;
326  pivot = begin + num_left;
327  left_bb = lbb;
328  right_bb = rbb;
329  }
330  }
331 
332  if (min_dim == -1)
333  return false;
334 
335  // Compute the cost for the current node.
336  const float curr_cost = area( node.m_bbox ) * n_entities;
337 
338  // Don't split if the split is more expensive than the current node.
339  if (m_force_splitting == false && curr_cost * 1.5f < min_cost /*TODO: remove magic constant*/ )
340  return false;
341 
342  // Tag the entities whether they're left or right according to the winner split.
343  const int* indices_ptr = &m_indices[min_dim][0];
344  for (uint32 i = begin; i < pivot; ++i)
345  m_tag_bits[indices_ptr[i]] = false;
346  for (uint32 i = pivot; i < end; ++i)
347  m_tag_bits[indices_ptr[i]] = true;
348 
349  // Rearrange the indices of the non-winner dimensions to sorted left/right.
350  for (int d = 1; d <= 2; ++d)
351  {
352  const int dim = (min_dim+d) % 3;
353  int leftpos = begin;
354  int rightpos = pivot;
355 
356  const int* indices_ptr = &m_indices[dim][0];
357  for (uint32 i = begin; i < end; ++i)
358  {
359  const int index = indices_ptr[i];
360 
361  if (m_tag_bits[index])
362  m_tmpInt[rightpos++] = index;
363  else
364  m_tmpInt[leftpos++] = index;
365  }
366 
367  // Copy the working array back to indices.
368  memcpy( &m_indices[dim][begin], &m_tmpInt[begin], sizeof(int)*n_entities );
369  }
370  return true;
371 }
372 
373 inline bool Bvh_sah_builder::find_best_split(
374  const Node& node,
375  uint32& pivot,
376  bbox_type& left_bb,
377  bbox_type& right_bb)
378 {
379  const uint32 begin = node.m_begin;
380  const uint32 end = node.m_end;
381  const uint32 n_entities = end - begin;
382 
383  if (n_entities > m_single_axis_threshold)
384  return find_largest_axis_split( node, pivot, left_bb, right_bb );
385 
386  if (m_bboxes.size() < n_entities+1)
387  m_bboxes.resize( n_entities+1 );
388  if (m_costs.size() < n_entities+1)
389  m_costs.resize( n_entities+1 );
390 
391  float min_cost = std::numeric_limits<float>::max();
392  int min_dim = -1;
393 
394  // Find the least costly split for each dimension.
395  for(int dim = 0; dim < 3; ++dim)
396  {
397  Predicate predicate( dim );
398 
399  m_bboxes[0] = bbox_type();
400  m_costs[0] = 0.0f;
401 
402  std::vector<int>& indices = m_indices[dim];
403 
404  // Accumulate right hand side bboxes.
405  for(uint32 i = 1; i <= n_entities; ++i)
406  m_bboxes[i] = bbox_type( m_bboxes[i-1], m_entities[ indices[ end - i ] ].m_bbox );
407 
408  for(uint32 i = 1; i <= n_entities; ++i)
409  m_costs[i] = m_costs[i-1] + m_entities[ indices[ end - i ] ].m_cost;
410 
411  // Loop over possible splits and find the cheapest one.
412  bbox_type lbb, rbb;
413  float lc = 0.0f, rc;
414 
415  for(uint32 num_left = 1; num_left < n_entities; ++num_left)
416  {
417  const int num_right = n_entities - num_left;
418 
419  rbb = m_bboxes[num_right];
420  lbb.insert( m_entities[ indices[ begin + num_left - 1 ] ].m_bbox );
421 
422  rc = m_costs[num_right];
423  lc += m_entities[ indices[ begin + num_left - 1 ] ].m_cost;
424 
425  if (m_force_alignment && (num_left % m_max_leaf_size != 0))
426  continue;
427 
428  const float sa_left = area( lbb );
429  const float sa_right = area( rbb );
430 
431  const float cost = sa_left*lc + sa_right*rc;
432 
433  if(cost < min_cost)
434  {
435  min_cost = cost;
436  min_dim = dim;
437  pivot = begin + num_left;
438  left_bb = lbb;
439  right_bb = rbb;
440  }
441  }
442  }
443 
444  if (min_dim == -1)
445  return false;
446 
447  // Compute the cost for the current node.
448  const float curr_cost = area( node.m_bbox ) * n_entities;
449 
450  // Don't split if the split is more expensive than the current node.
451  if (m_force_splitting == false && curr_cost * 1.5f < min_cost /*TODO: remove magic constant*/ )
452  return false;
453 
454  // Tag the entities whether they're left or right according to the winner split.
455  const int* indices_ptr = &m_indices[min_dim][0];
456  for (uint32 i = begin; i < pivot; ++i)
457  m_tag_bits[indices_ptr[i]] = false;
458  for (uint32 i = pivot; i < end; ++i)
459  m_tag_bits[indices_ptr[i]] = true;
460 
461  // Rearrange the indices of the non-winner dimensions to sorted left/right.
462  for (int d = 1; d <= 2; ++d)
463  {
464  const int dim = (min_dim+d) % 3;
465  int leftpos = begin;
466  int rightpos = pivot;
467 
468  const int* indices_ptr = &m_indices[dim][0];
469  for (uint32 i = begin; i < end; ++i)
470  {
471  const int index = indices_ptr[i];
472 
473  if (m_tag_bits[index])
474  m_tmpInt[rightpos++] = index;
475  else
476  m_tmpInt[leftpos++] = index;
477  }
478 
479  // Copy the working array back to indices.
480  memcpy( &m_indices[dim][begin], &m_tmpInt[begin], sizeof(int)*n_entities );
481  }
482  return true;
483 }
484 
485 inline void Bvh_sah_builder::compute_bbox(
486  const uint32 begin,
487  const uint32 end,
488  bbox_type& bbox)
489 {
490  bbox = bbox_type();
491  for (uint32 i = begin; i < end; i++)
492  bbox.insert( m_entities[m_indices[0][i]].m_bbox );
493 }
494 
495 namespace deprecated {
496 
497 template <typename Iterator>
499  const Iterator begin,
500  const Iterator end,
501  bvh_type* bvh)
502 {
503  m_entities.resize( end - begin );
504  uint32 i = 0;
505  for (Iterator it = begin; it != end; ++it)
506  {
507  m_entities[i].m_bbox = *it;
508  m_entities[i].m_index = i;
509 
510  i++;
511  }
512 
513  // create root
514  Node_stack node_stack;
515  {
516  Node node;
517  compute_bbox( 0u, uint32(end - begin), node.m_bbox );
518  node.m_begin = 0u;
519  node.m_end = uint32(end - begin);
520  node.m_depth = 0u;
521  node.m_node = 0u;
522 
523  node_stack.push( node );
524  }
525 
526  Bvh_node root;
527  root.set_type( Bvh_node::kLeaf );
528  root.set_index( 0u );
529  bvh->m_nodes.push_back( root );
530  bvh->m_bboxes.resize( 1u );
531 
532  while (node_stack.empty() == false)
533  {
534  const Node node = node_stack.top();
535  node_stack.pop();
536 
537  const uint32 node_index = node.m_node;
538  const bbox_type bbox = node.m_bbox;
539 
540  bvh->m_bboxes[ node_index ] = bbox;
541 
542  if (node.m_end - node.m_begin < m_max_leaf_size)
543  {
544  //
545  // Make a leaf node
546  //
547  Bvh_node& bvh_node = bvh->m_nodes[ node_index ];
548  bvh_node = Bvh_node( Bvh_node::kLeaf, node.m_begin, node.m_end );
549  }
550  else
551  {
552  //
553  // Make a split node
554  //
555 
556  uint32 middle;
557  bbox_type l_bb, r_bb;
558 
559  if (find_best_split( node, middle, l_bb, r_bb ) == false)
560  {
561  // unsuccessful split: make a leaf node
562  Bvh_node& bvh_node = bvh->m_nodes[ node_index ];
563  bvh_node = Bvh_node( Bvh_node::kLeaf, node.m_begin, node.m_end );
564  continue;
565  }
566 
567  // alloc space for children
568  const uint32 left_node_index = uint32( bvh->m_nodes.size() );
569  bvh->m_nodes.resize( left_node_index + 2 );
570  bvh->m_bboxes.resize( left_node_index + 2 );
571 
572  Bvh_node& bvh_node = bvh->m_nodes[ node_index ];
573  bvh_node = Bvh_node( Bvh_node::kInternal, left_node_index, node.m_end - node.m_begin );
574 
575  // push left and right children in processing queue
576  Node right_node;
577  right_node.m_bbox = r_bb;
578  right_node.m_begin = middle;
579  right_node.m_end = node.m_end;
580  right_node.m_depth = node.m_depth + 1u;
581  right_node.m_node = left_node_index + 1u;
582  node_stack.push( right_node );
583 
584  Node left_node;
585  left_node.m_bbox = l_bb;
586  left_node.m_begin = node.m_begin;
587  left_node.m_end = middle;
588  left_node.m_depth = node.m_depth + 1u;
589  left_node.m_node = left_node_index;
590  node_stack.push( left_node );
591  }
592  }
593 }
594 
595 
596 // Predicate to sort indices based on their entity's AABB center.
598 {
599 public:
600  Predicate(int dim) : m_dim( dim ) {}
601 
602  bool operator() (const Entity& lhs, const Entity& rhs) const
603  {
604  const float leftval = lhs.m_bbox[0][m_dim] + lhs.m_bbox[1][m_dim];
605  const float rightval = rhs.m_bbox[0][m_dim] + rhs.m_bbox[1][m_dim];
606 
607  return leftval < rightval;
608  }
609 
610 private:
611  int m_dim;
612 };
613 
614 inline float Bvh_sah_builder::area(const Bbox3f& bbox)
615 {
616  const Vector3f edge = bbox[1] - bbox[0];
617  return edge[0] * edge[1] + edge[2] * (edge[0] + edge[1]);
618 }
619 
620 inline bool Bvh_sah_builder::find_best_split(
621  const Node& node,
622  uint32& pivot,
623  bbox_type& left_bb,
624  bbox_type& right_bb)
625 {
626  float min_cost = std::numeric_limits<float>::max();
627  int min_dim = -1;
628 
629  const uint32 begin = node.m_begin;
630  const uint32 end = node.m_end;
631  const uint32 n_entities = end - begin;
632  if (m_bboxes.size() < n_entities+1)
633  m_bboxes.resize( n_entities+1 );
634 
635  // Find the least costly split for each dimension.
636  for(int dim = 0; dim < 3; ++dim)
637  {
638  Predicate predicate( dim );
639 
640  // Sort along current dimension.
641  std::sort(
642  &m_entities[0] + begin,
643  &m_entities[0] + end,
644  predicate );
645 
646  m_bboxes[0].clear();
647 
648  // Accumulate right hand side bboxes.
649  for(uint32 i = 1; i <= n_entities; ++i)
650  {
651  m_bboxes[i] = m_bboxes[i-1];
652  m_bboxes[i].insert( m_entities[ end - i ].m_bbox );
653  }
654 
655  // Loop over possible splits and find the cheapest one.
656  bbox_type lbb, rbb;
657 
658  for(uint32 num_left = 1; num_left < n_entities; ++num_left)
659  {
660  const int num_right = n_entities - num_left;
661 
662  rbb = m_bboxes[num_right];
663  lbb.insert( m_entities[ begin + num_left - 1 ].m_bbox );
664 
665  const float sa_left = area( lbb );
666  const float sa_right = area( rbb );
667 
668  const float cost = sa_left*num_left + sa_right*num_right;
669 
670  if(cost < min_cost)
671  {
672  min_cost = cost;
673  min_dim = dim;
674  pivot = begin + num_left;
675  left_bb = lbb;
676  right_bb = rbb;
677  }
678  }
679  }
680 
681  // Compute the cost for the current node.
682  const float curr_cost = area( node.m_bbox ) * n_entities;
683 
684  // Don't split if the split is more expensive than the current node.
685  if( curr_cost * 1.5f < min_cost)
686  return false;
687 
688  // Resort if necessary.
689  if(min_dim != 2)
690  {
691  Predicate predicate( min_dim );
692  std::sort(
693  &m_entities[0] + begin,
694  &m_entities[0] + end,
695  predicate );
696  }
697  return true;
698 }
699 
700 inline void Bvh_sah_builder::compute_bbox(
701  const uint32 begin,
702  const uint32 end,
703  bbox_type& bbox)
704 {
705  bbox.clear();
706  for (uint32 i = begin; i < end; i++)
707  bbox.insert( m_entities[i].m_bbox );
708 }
709 
710 } // namespace deprecated
711 
712 } // namespace cugar
Vector_t m_max
max corner
Definition: bbox.h:126
CUGAR_HOST CUGAR_DEVICE void clear()
Definition: bbox_inline.h:85
thrust::device_vector< T >::iterator begin(thrust::device_vector< T > &vec)
Definition: thrust_view.h:89
Definition: bvh_node.h:45
Definition: bvh.h:84
Vector_t m_min
min corner
Definition: bbox.h:125
Define a vector_view POD type and plain_view() for std::vector.
Definition: diff.h:38
Definition: bvh_sah_builder.h:51
void build(Iterator begin, Iterator end, bvh_type *bvh, Stats *stats=NULL)
Definition: bvh_sah_builder_inline.h:187
CUGAR_HOST_DEVICE float area(const Bbox2f &bbox)
Definition: bbox_inline.h:134
Definition: bvh_sah_builder_inline.h:35
Definition: bvh_sah_builder_inline.h:240
Definition: bvh_sah_builder_inline.h:597
CUGAR_HOST CUGAR_DEVICE void insert(const Vector_t &v)
Definition: bbox_inline.h:65
uint32 index(const uint32 i) const
remapped point index
Definition: bvh_sah_builder.h:105