Blender  V2.93
bvh_build.cpp
Go to the documentation of this file.
1 /*
2  * Adapted from code copyright 2009-2010 NVIDIA Corporation
3  * Modifications Copyright 2011, Blender Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "bvh/bvh_build.h"
19 
20 #include "bvh/bvh_binning.h"
21 #include "bvh/bvh_node.h"
22 #include "bvh/bvh_params.h"
23 #include "bvh_split.h"
24 
25 #include "render/curves.h"
26 #include "render/hair.h"
27 #include "render/mesh.h"
28 #include "render/object.h"
29 #include "render/scene.h"
30 
31 #include "util/util_algorithm.h"
32 #include "util/util_foreach.h"
33 #include "util/util_logging.h"
34 #include "util/util_progress.h"
35 #include "util/util_queue.h"
36 #include "util/util_simd.h"
38 #include "util/util_time.h"
39 
41 
42 /* Constructor / Destructor */
43 
45  array<int> &prim_type_,
46  array<int> &prim_index_,
47  array<int> &prim_object_,
48  array<float2> &prim_time_,
49  const BVHParams &params_,
50  Progress &progress_)
51  : objects(objects_),
52  prim_type(prim_type_),
53  prim_index(prim_index_),
54  prim_object(prim_object_),
55  prim_time(prim_time_),
56  params(params_),
57  progress(progress_),
58  progress_start_time(0.0),
59  unaligned_heuristic(objects_)
60 {
61  spatial_min_overlap = 0.0f;
62 }
63 
65 {
66 }
67 
68 /* Adding References */
69 
71 {
72  const Attribute *attr_mP = NULL;
73  if (mesh->has_motion_blur()) {
75  }
76  const size_t num_triangles = mesh->num_triangles();
77  for (uint j = 0; j < num_triangles; j++) {
79  const float3 *verts = &mesh->verts[0];
80  if (attr_mP == NULL) {
82  t.bounds_grow(verts, bounds);
83  if (bounds.valid() && t.valid(verts)) {
85  root.grow(bounds);
86  center.grow(bounds.center2());
87  }
88  }
90  /* Motion triangles, simple case: single node for the whole
91  * primitive. Lowest memory footprint and faster BVH build but
92  * least optimal ray-tracing.
93  */
94  /* TODO(sergey): Support motion steps for spatially split BVH. */
95  const size_t num_verts = mesh->verts.size();
96  const size_t num_steps = mesh->motion_steps;
97  const float3 *vert_steps = attr_mP->data_float3();
99  t.bounds_grow(verts, bounds);
100  for (size_t step = 0; step < num_steps - 1; step++) {
101  t.bounds_grow(vert_steps + step * num_verts, bounds);
102  }
103  if (bounds.valid()) {
105  root.grow(bounds);
106  center.grow(bounds.center2());
107  }
108  }
109  else {
110  /* Motion triangles, trace optimized case: we split triangle
111  * primitives into separate nodes for each of the time steps.
112  * This way we minimize overlap of neighbor curve primitives.
113  */
114  const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
115  const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
116  const size_t num_verts = mesh->verts.size();
117  const size_t num_steps = mesh->motion_steps;
118  const float3 *vert_steps = attr_mP->data_float3();
119  /* Calculate bounding box of the previous time step.
120  * Will be reused later to avoid duplicated work on
121  * calculating BVH time step boundbox.
122  */
123  float3 prev_verts[3];
124  t.motion_verts(verts, vert_steps, num_verts, num_steps, 0.0f, prev_verts);
125  BoundBox prev_bounds = BoundBox::empty;
126  prev_bounds.grow(prev_verts[0]);
127  prev_bounds.grow(prev_verts[1]);
128  prev_bounds.grow(prev_verts[2]);
129  /* Create all primitive time steps, */
130  for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
131  const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
132  float3 curr_verts[3];
133  t.motion_verts(verts, vert_steps, num_verts, num_steps, curr_time, curr_verts);
134  BoundBox curr_bounds = BoundBox::empty;
135  curr_bounds.grow(curr_verts[0]);
136  curr_bounds.grow(curr_verts[1]);
137  curr_bounds.grow(curr_verts[2]);
138  BoundBox bounds = prev_bounds;
139  bounds.grow(curr_bounds);
140  if (bounds.valid()) {
141  const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
142  references.push_back(
143  BVHReference(bounds, j, i, PRIMITIVE_MOTION_TRIANGLE, prev_time, curr_time));
144  root.grow(bounds);
145  center.grow(bounds.center2());
146  }
147  /* Current time boundbox becomes previous one for the
148  * next time step.
149  */
150  prev_bounds = curr_bounds;
151  }
152  }
153  }
154 }
155 
157 {
158  const Attribute *curve_attr_mP = NULL;
159  if (hair->has_motion_blur()) {
160  curve_attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
161  }
162 
163  const PrimitiveType primitive_type =
164  (curve_attr_mP != NULL) ?
168 
169  const size_t num_curves = hair->num_curves();
170  for (uint j = 0; j < num_curves; j++) {
171  const Hair::Curve curve = hair->get_curve(j);
172  const float *curve_radius = &hair->get_curve_radius()[0];
173  for (int k = 0; k < curve.num_keys - 1; k++) {
174  if (curve_attr_mP == NULL) {
175  /* Really simple logic for static hair. */
177  curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
178  if (bounds.valid()) {
179  int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
180  references.push_back(BVHReference(bounds, j, i, packed_type));
181  root.grow(bounds);
182  center.grow(bounds.center2());
183  }
184  }
186  /* Simple case of motion curves: single node for the while
187  * shutter time. Lowest memory usage but less optimal
188  * rendering.
189  */
190  /* TODO(sergey): Support motion steps for spatially split BVH. */
192  curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
193  const size_t num_keys = hair->get_curve_keys().size();
194  const size_t num_steps = hair->get_motion_steps();
195  const float3 *key_steps = curve_attr_mP->data_float3();
196  for (size_t step = 0; step < num_steps - 1; step++) {
197  curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds);
198  }
199  if (bounds.valid()) {
200  int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
201  references.push_back(BVHReference(bounds, j, i, packed_type));
202  root.grow(bounds);
203  center.grow(bounds.center2());
204  }
205  }
206  else {
207  /* Motion curves, trace optimized case: we split curve keys
208  * primitives into separate nodes for each of the time steps.
209  * This way we minimize overlap of neighbor curve primitives.
210  */
211  const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
212  const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
213  const size_t num_steps = hair->get_motion_steps();
214  const float3 *curve_keys = &hair->get_curve_keys()[0];
215  const float3 *key_steps = curve_attr_mP->data_float3();
216  const size_t num_keys = hair->get_curve_keys().size();
217  /* Calculate bounding box of the previous time step.
218  * Will be reused later to avoid duplicated work on
219  * calculating BVH time step boundbox.
220  */
221  float4 prev_keys[4];
222  curve.cardinal_motion_keys(curve_keys,
223  curve_radius,
224  key_steps,
225  num_keys,
226  num_steps,
227  0.0f,
228  k - 1,
229  k,
230  k + 1,
231  k + 2,
232  prev_keys);
233  BoundBox prev_bounds = BoundBox::empty;
234  curve.bounds_grow(prev_keys, prev_bounds);
235  /* Create all primitive time steps, */
236  for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
237  const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
238  float4 curr_keys[4];
239  curve.cardinal_motion_keys(curve_keys,
240  curve_radius,
241  key_steps,
242  num_keys,
243  num_steps,
244  curr_time,
245  k - 1,
246  k,
247  k + 1,
248  k + 2,
249  curr_keys);
250  BoundBox curr_bounds = BoundBox::empty;
251  curve.bounds_grow(curr_keys, curr_bounds);
252  BoundBox bounds = prev_bounds;
253  bounds.grow(curr_bounds);
254  if (bounds.valid()) {
255  const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
256  int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
257  references.push_back(BVHReference(bounds, j, i, packed_type, prev_time, curr_time));
258  root.grow(bounds);
259  center.grow(bounds.center2());
260  }
261  /* Current time boundbox becomes previous one for the
262  * next time step.
263  */
264  prev_bounds = curr_bounds;
265  }
266  }
267  }
268  }
269 }
270 
272 {
273  if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
274  Mesh *mesh = static_cast<Mesh *>(geom);
276  }
277  else if (geom->geometry_type == Geometry::HAIR) {
278  Hair *hair = static_cast<Hair *>(geom);
279  add_reference_curves(root, center, hair, i);
280  }
281 }
282 
284 {
285  references.push_back(BVHReference(ob->bounds, -1, i, 0));
286  root.grow(ob->bounds);
287  center.grow(ob->bounds.center2());
288 }
289 
290 static size_t count_curve_segments(Hair *hair)
291 {
292  size_t num = 0, num_curves = hair->num_curves();
293 
294  for (size_t i = 0; i < num_curves; i++)
295  num += hair->get_curve(i).num_keys - 1;
296 
297  return num;
298 }
299 
300 static size_t count_primitives(Geometry *geom)
301 {
302  if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
303  Mesh *mesh = static_cast<Mesh *>(geom);
304  return mesh->num_triangles();
305  }
306  else if (geom->geometry_type == Geometry::HAIR) {
307  Hair *hair = static_cast<Hair *>(geom);
308  return count_curve_segments(hair);
309  }
310 
311  return 0;
312 }
313 
315 {
316  /* reserve space for references */
317  size_t num_alloc_references = 0;
318 
319  foreach (Object *ob, objects) {
320  if (params.top_level) {
321  if (!ob->is_traceable()) {
322  continue;
323  }
324  if (!ob->get_geometry()->is_instanced()) {
325  num_alloc_references += count_primitives(ob->get_geometry());
326  }
327  else
328  num_alloc_references++;
329  }
330  else {
331  num_alloc_references += count_primitives(ob->get_geometry());
332  }
333  }
334 
335  references.reserve(num_alloc_references);
336 
337  /* add references from objects */
339  int i = 0;
340 
341  foreach (Object *ob, objects) {
342  if (params.top_level) {
343  if (!ob->is_traceable()) {
344  ++i;
345  continue;
346  }
347  if (!ob->get_geometry()->is_instanced())
348  add_reference_geometry(bounds, center, ob->get_geometry(), i);
349  else
351  }
352  else
353  add_reference_geometry(bounds, center, ob->get_geometry(), i);
354 
355  i++;
356 
357  if (progress.get_cancel())
358  return;
359  }
360 
361  /* happens mostly on empty meshes */
362  if (!bounds.valid())
363  bounds.grow(zero_float3());
364 
365  root = BVHRange(bounds, center, 0, references.size());
366 }
367 
368 /* Build */
369 
371 {
372  BVHRange root;
373 
374  /* add references */
375  add_references(root);
376 
377  if (progress.get_cancel())
378  return NULL;
379 
380  /* init spatial splits */
381  if (params.top_level) {
382  /* NOTE: Technically it is supported by the builder but it's not really
383  * optimized for speed yet and not really clear yet if it has measurable
384  * improvement on render time. Needs some extra investigation before
385  * enabling spatial split for top level BVH.
386  */
387  params.use_spatial_split = false;
388  }
389 
391  spatial_free_index = 0;
392 
394 
395  /* init progress updates */
396  double build_start_time;
397  build_start_time = progress_start_time = time_dt();
398  progress_count = 0;
399  progress_total = references.size();
401 
402  prim_type.resize(references.size());
403  prim_index.resize(references.size());
404  prim_object.resize(references.size());
405  if (need_prim_time) {
406  prim_time.resize(references.size());
407  }
408  else {
409  prim_time.resize(0);
410  }
411 
412  /* build recursively */
413  BVHNode *rootnode;
414 
416  /* Perform multithreaded spatial split build. */
417  BVHSpatialStorage *local_storage = &spatial_storage.local();
418  rootnode = build_node(root, references, 0, local_storage);
420  }
421  else {
422  /* Perform multithreaded binning build. */
423  BVHObjectBinning rootbin(root, (references.size()) ? &references[0] : NULL);
424  rootnode = build_node(rootbin, 0);
426  }
427 
428  /* clean up temporary memory usage by threads */
429  spatial_storage.clear();
430 
431  /* delete if we canceled */
432  if (rootnode) {
433  if (progress.get_cancel()) {
434  rootnode->deleteSubtree();
435  rootnode = NULL;
436  VLOG(1) << "BVH build cancelled.";
437  }
438  else {
439  /*rotate(rootnode, 4, 5);*/
440  rootnode->update_visibility();
441  rootnode->update_time();
442  }
443  if (rootnode != NULL) {
444  VLOG(1) << "BVH build statistics:\n"
445  << " Build time: " << time_dt() - build_start_time << "\n"
446  << " Total number of nodes: "
448  << "\n"
449  << " Number of inner nodes: "
451  << "\n"
452  << " Number of leaf nodes: "
454  << "\n"
455  << " Number of unaligned nodes: "
457  << "\n"
458  << " Allocation slop factor: "
459  << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
460  1.0f)
461  << "\n"
462  << " Maximum depth: "
464  }
465  }
466 
467  return rootnode;
468 }
469 
471 {
472  if (time_dt() - progress_start_time < 0.25)
473  return;
474 
475  double progress_start = (double)progress_count / (double)progress_total;
477 
478  string msg = string_printf(
479  "Building BVH %.0f%%, duplicates %.0f%%", progress_start * 100.0, duplicates * 100.0);
480 
481  progress.set_substatus(msg);
483 }
484 
486  int child,
487  const BVHObjectBinning &range,
488  int level)
489 {
490  if (progress.get_cancel())
491  return;
492 
493  /* build nodes */
494  BVHNode *node = build_node(range, level);
495 
496  /* set child in inner node */
497  inner->children[child] = node;
498 
499  /* update progress */
500  if (range.size() < THREAD_TASK_SIZE) {
501  /*rotate(node, INT_MAX, 5);*/
502 
504 
505  progress_count += range.size();
506  progress_update();
507  }
508 }
509 
511  int child,
512  const BVHRange &range,
513  vector<BVHReference> &references,
514  int level)
515 {
516  if (progress.get_cancel()) {
517  return;
518  }
519 
520  /* Get per-thread memory for spatial split. */
521  BVHSpatialStorage *local_storage = &spatial_storage.local();
522 
523  /* build nodes */
524  BVHNode *node = build_node(range, references, level, local_storage);
525 
526  /* set child in inner node */
527  inner->children[child] = node;
528 }
529 
531  const vector<BVHReference> &references) const
532 {
533  size_t size = range.size();
535 
536  if (size > max_leaf_size)
537  return false;
538 
539  size_t num_triangles = 0;
540  size_t num_motion_triangles = 0;
541  size_t num_curves = 0;
542  size_t num_motion_curves = 0;
543 
544  for (int i = 0; i < size; i++) {
545  const BVHReference &ref = references[range.start() + i];
546 
547  if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
548  if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
549  num_motion_curves++;
550  }
551  else {
552  num_curves++;
553  }
554  }
555  else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
556  if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
557  num_motion_triangles++;
558  }
559  else {
560  num_triangles++;
561  }
562  }
563  }
564 
565  return (num_triangles <= params.max_triangle_leaf_size) &&
566  (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
567  (num_curves <= params.max_curve_leaf_size) &&
568  (num_motion_curves <= params.max_motion_curve_leaf_size);
569 }
570 
571 /* multithreaded binning builder */
573 {
574  size_t size = range.size();
575  float leafSAH = params.sah_primitive_cost * range.leafSAH;
576  float splitSAH = params.sah_node_cost * range.bounds().half_area() +
578 
579  /* Have at least one inner node on top level, for performance and correct
580  * visibility tests, since object instances do not check visibility flag.
581  */
582  if (!(range.size() > 0 && params.top_level && level == 0)) {
583  /* Make leaf node when threshold reached or SAH tells us. */
584  if ((params.small_enough_for_leaf(size, level)) ||
585  (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) {
586  return create_leaf_node(range, references);
587  }
588  }
589 
590  BVHObjectBinning unaligned_range;
591  float unalignedSplitSAH = FLT_MAX;
592  float unalignedLeafSAH = FLT_MAX;
593  Transform aligned_space;
594  bool do_unalinged_split = false;
595  if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
596  aligned_space = unaligned_heuristic.compute_aligned_space(range, &references[0]);
597  unaligned_range = BVHObjectBinning(
598  range, &references[0], &unaligned_heuristic, &aligned_space);
599  unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
600  params.sah_primitive_cost * unaligned_range.splitSAH;
601  unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
602  if (!(range.size() > 0 && params.top_level && level == 0)) {
603  if (unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
605  return create_leaf_node(range, references);
606  }
607  }
608  /* Check whether unaligned split is better than the regular one. */
609  if (unalignedSplitSAH < splitSAH) {
610  do_unalinged_split = true;
611  }
612  }
613 
614  /* Perform split. */
616  if (do_unalinged_split) {
617  unaligned_range.split(&references[0], left, right);
618  }
619  else {
620  range.split(&references[0], left, right);
621  }
622 
624  if (do_unalinged_split) {
625  bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references[0], aligned_space);
626  }
627  else {
628  bounds = range.bounds();
629  }
630 
631  /* Create inner node. */
632  InnerNode *inner;
633  if (range.size() < THREAD_TASK_SIZE) {
634  /* local build */
635  BVHNode *leftnode = build_node(left, level + 1);
636  BVHNode *rightnode = build_node(right, level + 1);
637 
638  inner = new InnerNode(bounds, leftnode, rightnode);
639  }
640  else {
641  /* Threaded build */
642  inner = new InnerNode(bounds);
643 
644  task_pool.push([=] { thread_build_node(inner, 0, left, level + 1); });
645  task_pool.push([=] { thread_build_node(inner, 1, right, level + 1); });
646  }
647 
648  if (do_unalinged_split) {
649  inner->set_aligned_space(aligned_space);
650  }
651 
652  return inner;
653 }
654 
655 /* multithreaded spatial split builder */
657  vector<BVHReference> &references,
658  int level,
659  BVHSpatialStorage *storage)
660 {
661  /* Update progress.
662  *
663  * TODO(sergey): Currently it matches old behavior, but we can move it to the
664  * task thread (which will mimic non=split builder) and save some CPU ticks
665  * on checking cancel status.
666  */
667  progress_update();
668  if (progress.get_cancel()) {
669  return NULL;
670  }
671 
672  /* Small enough or too deep => create leaf. */
673  if (!(range.size() > 0 && params.top_level && level == 0)) {
674  if (params.small_enough_for_leaf(range.size(), level)) {
675  progress_count += range.size();
676  return create_leaf_node(range, references);
677  }
678  }
679 
680  /* Perform splitting test. */
681  BVHMixedSplit split(this, storage, range, references, level);
682 
683  if (!(range.size() > 0 && params.top_level && level == 0)) {
684  if (split.no_split) {
685  progress_count += range.size();
686  return create_leaf_node(range, references);
687  }
688  }
689  float leafSAH = params.sah_primitive_cost * split.leafSAH;
690  float splitSAH = params.sah_node_cost * range.bounds().half_area() +
691  params.sah_primitive_cost * split.nodeSAH;
692 
693  BVHMixedSplit unaligned_split;
694  float unalignedSplitSAH = FLT_MAX;
695  /* float unalignedLeafSAH = FLT_MAX; */
696  Transform aligned_space;
697  bool do_unalinged_split = false;
698  if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
699  aligned_space = unaligned_heuristic.compute_aligned_space(range, &references.at(0));
700  unaligned_split = BVHMixedSplit(
701  this, storage, range, references, level, &unaligned_heuristic, &aligned_space);
702  /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
703  unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
704  params.sah_primitive_cost * unaligned_split.nodeSAH;
705  /* TOOD(sergey): Check we can create leaf already. */
706  /* Check whether unaligned split is better than the regular one. */
707  if (unalignedSplitSAH < splitSAH) {
708  do_unalinged_split = true;
709  }
710  }
711 
712  /* Do split. */
714  if (do_unalinged_split) {
715  unaligned_split.split(this, left, right, range);
716  }
717  else {
718  split.split(this, left, right, range);
719  }
720 
721  progress_total += left.size() + right.size() - range.size();
722 
724  if (do_unalinged_split) {
725  bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references.at(0), aligned_space);
726  }
727  else {
728  bounds = range.bounds();
729  }
730 
731  /* Create inner node. */
732  InnerNode *inner;
733  if (range.size() < THREAD_TASK_SIZE) {
734  /* Local build. */
735 
736  /* Build left node. */
737  vector<BVHReference> right_references(references.begin() + right.start(),
738  references.begin() + right.end());
739  right.set_start(0);
740 
741  BVHNode *leftnode = build_node(left, references, level + 1, storage);
742 
743  /* Build right node. */
744  BVHNode *rightnode = build_node(right, right_references, level + 1, storage);
745 
746  inner = new InnerNode(bounds, leftnode, rightnode);
747  }
748  else {
749  /* Threaded build. */
750  inner = new InnerNode(bounds);
751 
752  vector<BVHReference> left_references(references.begin() + left.start(),
753  references.begin() + left.end());
754  vector<BVHReference> right_references(references.begin() + right.start(),
755  references.begin() + right.end());
756  right.set_start(0);
757 
758  /* Create tasks for left and right nodes, using copy for most arguments and
759  * move for reference to avoid memory copies. */
760  task_pool.push([=, refs = std::move(left_references)]() mutable {
761  thread_build_spatial_split_node(inner, 0, left, refs, level + 1);
762  });
763  task_pool.push([=, refs = std::move(right_references)]() mutable {
764  thread_build_spatial_split_node(inner, 1, right, refs, level + 1);
765  });
766  }
767 
768  if (do_unalinged_split) {
769  inner->set_aligned_space(aligned_space);
770  }
771 
772  return inner;
773 }
774 
775 /* Create Nodes */
776 
778 {
779  if (num == 0) {
781  return new LeafNode(bounds, 0, 0, 0);
782  }
783  else if (num == 1) {
784  assert(start < prim_type.size());
785  prim_type[start] = ref->prim_type();
786  prim_index[start] = ref->prim_index();
787  prim_object[start] = ref->prim_object();
788  if (need_prim_time) {
789  prim_time[start] = make_float2(ref->time_from(), ref->time_to());
790  }
791 
792  const uint visibility = objects[ref->prim_object()]->visibility_for_tracing();
793  BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start + 1);
794  leaf_node->time_from = ref->time_from();
795  leaf_node->time_to = ref->time_to();
796  return leaf_node;
797  }
798  else {
799  int mid = num / 2;
800  BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
801  BVHNode *leaf1 = create_object_leaf_nodes(ref + mid, start + mid, num - mid);
802 
804  bounds.grow(leaf0->bounds);
805  bounds.grow(leaf1->bounds);
806 
807  BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
808  inner_node->time_from = min(leaf0->time_from, leaf1->time_from);
809  inner_node->time_to = max(leaf0->time_to, leaf1->time_to);
810  return inner_node;
811  }
812 }
813 
815 {
816  /* This is a bit overallocating here (considering leaf size into account),
817  * but chunk-based re-allocation in vector makes it difficult to use small
818  * size of stack storage here. Some tweaks are possible tho.
819  *
820  * NOTES:
821  * - If the size is too big, we'll have inefficient stack usage,
822  * and lots of cache misses.
823  * - If the size is too small, then we can run out of memory
824  * allowed to be used by vector.
825  * In practice it wouldn't mean crash, just allocator will fallback
826  * to heap which is slower.
827  * - Optimistic re-allocation in STL could jump us out of stack usage
828  * because re-allocation happens in chunks and size of those chunks we
829  * can not control.
830  */
831  typedef StackAllocator<256, int> LeafStackAllocator;
832  typedef StackAllocator<256, float2> LeafTimeStackAllocator;
833  typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
834 
840 
841  /* TODO(sergey): In theory we should be able to store references. */
843 
844  uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
845  /* NOTE: Keep initialization in sync with actual number of primitives. */
848  int ob_num = 0;
849  int num_new_prims = 0;
850  /* Fill in per-type type/index array. */
851  for (int i = 0; i < range.size(); i++) {
852  const BVHReference &ref = references[range.start() + i];
853  if (ref.prim_index() != -1) {
854  uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL));
855  p_ref[type_index].push_back(ref);
856  p_type[type_index].push_back(ref.prim_type());
857  p_index[type_index].push_back(ref.prim_index());
858  p_object[type_index].push_back(ref.prim_object());
859  p_time[type_index].push_back(make_float2(ref.time_from(), ref.time_to()));
860 
861  bounds[type_index].grow(ref.bounds());
862  visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing();
863  ++num_new_prims;
864  }
865  else {
866  object_references.push_back(ref);
867  ++ob_num;
868  }
869  }
870 
871  /* Create leaf nodes for every existing primitive.
872  *
873  * Here we write primitive types, indices and objects to a temporary array.
874  * This way we keep all the heavy memory allocation code outside of the
875  * thread lock in the case of spatial split building.
876  *
877  * TODO(sergey): With some pointer trickery we can write directly to the
878  * destination buffers for the non-spatial split BVH.
879  */
880  BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
881  int num_leaves = 0;
882  size_t start_index = 0;
883  vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
885  local_prim_type.resize(num_new_prims);
886  local_prim_index.resize(num_new_prims);
887  local_prim_object.resize(num_new_prims);
888  if (need_prim_time) {
889  local_prim_time.resize(num_new_prims);
890  }
891  for (int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
892  int num = (int)p_type[i].size();
893  if (num != 0) {
894  assert(p_type[i].size() == p_index[i].size());
895  assert(p_type[i].size() == p_object[i].size());
896  Transform aligned_space;
897  bool alignment_found = false;
898  for (int j = 0; j < num; ++j) {
899  const int index = start_index + j;
900  local_prim_type[index] = p_type[i][j];
901  local_prim_index[index] = p_index[i][j];
902  local_prim_object[index] = p_object[i][j];
903  if (need_prim_time) {
904  local_prim_time[index] = p_time[i][j];
905  }
906  if (params.use_unaligned_nodes && !alignment_found) {
907  alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], &aligned_space);
908  }
909  }
910  LeafNode *leaf_node = new LeafNode(bounds[i], visibility[i], start_index, start_index + num);
911  if (true) {
912  float time_from = 1.0f, time_to = 0.0f;
913  for (int j = 0; j < num; ++j) {
914  const BVHReference &ref = p_ref[i][j];
915  time_from = min(time_from, ref.time_from());
916  time_to = max(time_to, ref.time_to());
917  }
918  leaf_node->time_from = time_from;
919  leaf_node->time_to = time_to;
920  }
921  if (alignment_found) {
922  /* Need to recalculate leaf bounds with new alignment. */
923  leaf_node->bounds = BoundBox::empty;
924  for (int j = 0; j < num; ++j) {
925  const BVHReference &ref = p_ref[i][j];
927  aligned_space);
928  leaf_node->bounds.grow(ref_bounds);
929  }
930  /* Set alignment space. */
931  leaf_node->set_aligned_space(aligned_space);
932  }
933  leaves[num_leaves++] = leaf_node;
934  start_index += num;
935  }
936  }
937  /* Get size of new data to be copied to the packed arrays. */
938  const int num_new_leaf_data = start_index;
939  const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
940  /* Copy actual data to the packed array. */
942  spatial_spin_lock.lock();
943  /* We use first free index in the packed arrays and mode pointer to the
944  * end of the current range.
945  *
946  * This doesn't give deterministic packed arrays, but it shouldn't really
947  * matter because order of children in BVH is deterministic.
948  */
949  start_index = spatial_free_index;
950  spatial_free_index += range.size();
951  /* Extend an array when needed. */
952  const size_t range_end = start_index + range.size();
953  if (prim_type.size() < range_end) {
954  /* Avoid extra re-allocations by pre-allocating bigger array in an
955  * advance.
956  */
957  if (range_end >= prim_type.capacity()) {
958  float progress = (float)progress_count / (float)progress_total;
959  float factor = (1.0f - progress);
960  const size_t reserve = (size_t)(range_end + (float)range_end * factor);
961  prim_type.reserve(reserve);
962  prim_index.reserve(reserve);
963  prim_object.reserve(reserve);
964  if (need_prim_time) {
965  prim_time.reserve(reserve);
966  }
967  }
968 
969  prim_type.resize(range_end);
970  prim_index.resize(range_end);
971  prim_object.resize(range_end);
972  if (need_prim_time) {
973  prim_time.resize(range_end);
974  }
975  }
976  /* Perform actual data copy. */
977  if (new_leaf_data_size > 0) {
978  memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
979  memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
980  memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
981  if (need_prim_time) {
982  memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
983  }
984  }
985  spatial_spin_lock.unlock();
986  }
987  else {
988  /* For the regular BVH builder we simply copy new data starting at the
989  * range start. This is totally thread-safe, all threads are living
990  * inside of their own range.
991  */
992  start_index = range.start();
993  if (new_leaf_data_size > 0) {
994  memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
995  memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
996  memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
997  if (need_prim_time) {
998  memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
999  }
1000  }
1001  }
1002 
1003  /* So far leaves were created with the zero-based index in an arrays,
1004  * here we modify the indices to correspond to actual packed array start
1005  * index.
1006  */
1007  for (int i = 0; i < num_leaves; ++i) {
1008  LeafNode *leaf = (LeafNode *)leaves[i];
1009  leaf->lo += start_index;
1010  leaf->hi += start_index;
1011  }
1012 
1013  /* Create leaf node for object. */
1014  if (num_leaves == 0 || ob_num) {
1015  /* Only create object leaf nodes if there are objects or no other
1016  * nodes created.
1017  */
1018  const BVHReference *ref = (ob_num) ? &object_references[0] : NULL;
1019  leaves[num_leaves] = create_object_leaf_nodes(ref, start_index + num_new_leaf_data, ob_num);
1020  ++num_leaves;
1021  }
1022 
1023  /* TODO(sergey): Need to take care of alignment when number of leaves
1024  * is more than 1.
1025  */
1026  if (num_leaves == 1) {
1027  /* Simplest case: single leaf, just return it.
1028  * In all the rest cases we'll be creating intermediate inner node with
1029  * an appropriate bounding box.
1030  */
1031  return leaves[0];
1032  }
1033  else if (num_leaves == 2) {
1034  return new InnerNode(range.bounds(), leaves[0], leaves[1]);
1035  }
1036  else if (num_leaves == 3) {
1037  BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds);
1038  BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
1039  return new InnerNode(range.bounds(), leaves[0], inner);
1040  }
1041  else {
1042  /* Should be doing more branches if more primitive types added. */
1043  assert(num_leaves <= 5);
1044  BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds);
1045  BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds);
1046  BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
1047  BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
1048  BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds);
1049  BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
1050  if (num_leaves == 5) {
1051  return new InnerNode(range.bounds(), inner_c, leaves[4]);
1052  }
1053  return inner_c;
1054  }
1055 
1056 #undef MAX_ITEMS_PER_LEAF
1057 }
1058 
1059 /* Tree Rotations */
1060 
1061 void BVHBuild::rotate(BVHNode *node, int max_depth, int iterations)
1062 {
1063  /* in tested scenes, this resulted in slightly slower raytracing, so disabled
1064  * it for now. could be implementation bug, or depend on the scene */
1065  if (node)
1066  for (int i = 0; i < iterations; i++)
1067  rotate(node, max_depth);
1068 }
1069 
1070 void BVHBuild::rotate(BVHNode *node, int max_depth)
1071 {
1072  /* nothing to rotate if we reached a leaf node. */
1073  if (node->is_leaf() || max_depth < 0)
1074  return;
1075 
1076  InnerNode *parent = (InnerNode *)node;
1077 
1078  /* rotate all children first */
1079  for (size_t c = 0; c < 2; c++)
1080  rotate(parent->children[c], max_depth - 1);
1081 
1082  /* compute current area of all children */
1083  BoundBox bounds0 = parent->children[0]->bounds;
1084  BoundBox bounds1 = parent->children[1]->bounds;
1085 
1086  float area0 = bounds0.half_area();
1087  float area1 = bounds1.half_area();
1088  float4 child_area = make_float4(area0, area1, 0.0f, 0.0f);
1089 
1090  /* find best rotation. we pick a target child of a first child, and swap
1091  * this with an other child. we perform the best such swap. */
1092  float best_cost = FLT_MAX;
1093  int best_child = -1, best_target = -1, best_other = -1;
1094 
1095  for (size_t c = 0; c < 2; c++) {
1096  /* ignore leaf nodes as we cannot descent into */
1097  if (parent->children[c]->is_leaf())
1098  continue;
1099 
1100  InnerNode *child = (InnerNode *)parent->children[c];
1101  BoundBox &other = (c == 0) ? bounds1 : bounds0;
1102 
1103  /* transpose child bounds */
1104  BoundBox target0 = child->children[0]->bounds;
1105  BoundBox target1 = child->children[1]->bounds;
1106 
1107  /* compute cost for both possible swaps */
1108  float cost0 = merge(other, target1).half_area() - child_area[c];
1109  float cost1 = merge(target0, other).half_area() - child_area[c];
1110 
1111  if (min(cost0, cost1) < best_cost) {
1112  best_child = (int)c;
1113  best_other = (int)(1 - c);
1114 
1115  if (cost0 < cost1) {
1116  best_cost = cost0;
1117  best_target = 0;
1118  }
1119  else {
1120  best_cost = cost0;
1121  best_target = 1;
1122  }
1123  }
1124  }
1125 
1126  /* if we did not find a swap that improves the SAH then do nothing */
1127  if (best_cost >= 0)
1128  return;
1129 
1130  assert(best_child == 0 || best_child == 1);
1131  assert(best_target != -1);
1132 
1133  /* perform the best found tree rotation */
1134  InnerNode *child = (InnerNode *)parent->children[best_child];
1135 
1136  swap(parent->children[best_other], child->children[best_target]);
1137  child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds);
1138 }
1139 
typedef float(TangentPoint)[2]
unsigned int uint
Definition: BLI_sys_types.h:83
typedef double(DMatrix)[4][4]
void swap(T &a, T &b)
Definition: Common.h:33
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
static size_t count_primitives(Geometry *geom)
Definition: bvh_build.cpp:300
static size_t count_curve_segments(Hair *hair)
Definition: bvh_build.cpp:290
@ BVH_STAT_NODE_COUNT
Definition: bvh_node.h:27
@ BVH_STAT_DEPTH
Definition: bvh_node.h:38
@ BVH_STAT_UNALIGNED_COUNT
Definition: bvh_node.h:33
@ BVH_STAT_INNER_COUNT
Definition: bvh_node.h:28
@ BVH_STAT_LEAF_COUNT
Definition: bvh_node.h:29
Attribute * find(ustring name) const
Definition: attribute.cpp:447
float3 * data_float3()
Definition: attribute.h:86
BVHNode * create_object_leaf_nodes(const BVHReference *ref, int start, int num)
Definition: bvh_build.cpp:777
BVHNode * create_leaf_node(const BVHRange &range, const vector< BVHReference > &references)
Definition: bvh_build.cpp:814
void thread_build_spatial_split_node(InnerNode *node, int child, const BVHRange &range, vector< BVHReference > &references, int level)
Definition: bvh_build.cpp:510
size_t progress_count
Definition: bvh_build.h:123
BVHBuild(const vector< Object * > &objects, array< int > &prim_type, array< int > &prim_index, array< int > &prim_object, array< float2 > &prim_time, const BVHParams &params, Progress &progress)
Definition: bvh_build.cpp:44
bool range_within_max_leaf_size(const BVHRange &range, const vector< BVHReference > &references) const
Definition: bvh_build.cpp:530
thread_spin_lock spatial_spin_lock
Definition: bvh_build.h:131
thread_mutex build_mutex
Definition: bvh_build.h:95
void add_references(BVHRange &root)
Definition: bvh_build.cpp:314
void add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i)
Definition: bvh_build.cpp:283
BVHNode * build_node(const BVHRange &range, vector< BVHReference > &references, int level, BVHSpatialStorage *storage)
Definition: bvh_build.cpp:656
void add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair, int i)
Definition: bvh_build.cpp:156
bool need_prim_time
Definition: bvh_build.h:115
size_t spatial_free_index
Definition: bvh_build.h:130
BVHUnaligned unaligned_heuristic
Definition: bvh_build.h:137
BVHNode * run()
Definition: bvh_build.cpp:370
TaskPool task_pool
Definition: bvh_build.h:134
void add_reference_geometry(BoundBox &root, BoundBox &center, Geometry *geom, int i)
Definition: bvh_build.cpp:271
friend class BVHObjectBinning
Definition: bvh_build.h:66
Progress & progress
Definition: bvh_build.h:121
array< float2 > & prim_time
Definition: bvh_build.h:113
vector< Object * > objects
Definition: bvh_build.h:105
array< int > & prim_index
Definition: bvh_build.h:111
void rotate(BVHNode *node, int max_depth)
Definition: bvh_build.cpp:1070
enumerable_thread_specific< BVHSpatialStorage > spatial_storage
Definition: bvh_build.h:129
size_t progress_total
Definition: bvh_build.h:124
size_t progress_original_total
Definition: bvh_build.h:125
BVHParams params
Definition: bvh_build.h:118
void thread_build_node(InnerNode *node, int child, const BVHObjectBinning &range, int level)
Definition: bvh_build.cpp:485
float spatial_min_overlap
Definition: bvh_build.h:128
@ THREAD_TASK_SIZE
Definition: bvh_build.h:88
array< int > & prim_type
Definition: bvh_build.h:110
double progress_start_time
Definition: bvh_build.h:122
array< int > & prim_object
Definition: bvh_build.h:112
void progress_update()
Definition: bvh_build.cpp:470
friend class BVHMixedSplit
Definition: bvh_build.h:61
vector< BVHReference > references
Definition: bvh_build.h:106
void add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i)
Definition: bvh_build.cpp:70
__forceinline void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range)
Definition: bvh_split.h:226
float nodeSAH
Definition: bvh_split.h:176
BoundBox bounds
Definition: bvh_split.h:181
void split(BVHReference *prims, BVHObjectBinning &left_o, BVHObjectBinning &right_o) const
__forceinline const BoundBox & unaligned_bounds()
Definition: bvh_binning.h:50
bool use_spatial_split
Definition: bvh_params.h:49
int max_triangle_leaf_size
Definition: bvh_params.h:61
int num_motion_triangle_steps
Definition: bvh_params.h:86
float spatial_split_alpha
Definition: bvh_params.h:50
__forceinline bool small_enough_for_leaf(int size, int level)
Definition: bvh_params.h:143
int max_curve_leaf_size
Definition: bvh_params.h:63
bool use_unaligned_nodes
Definition: bvh_params.h:75
int max_motion_curve_leaf_size
Definition: bvh_params.h:64
int max_motion_triangle_leaf_size
Definition: bvh_params.h:62
float sah_node_cost
Definition: bvh_params.h:56
float sah_primitive_cost
Definition: bvh_params.h:57
bool top_level
Definition: bvh_params.h:67
float unaligned_split_threshold
Definition: bvh_params.h:53
int num_motion_curve_steps
Definition: bvh_params.h:83
__forceinline int size() const
Definition: bvh_params.h:266
__forceinline int start() const
Definition: bvh_params.h:262
__forceinline const BoundBox & bounds() const
Definition: bvh_params.h:254
__forceinline int prim_type() const
Definition: bvh_params.h:192
__forceinline int prim_object() const
Definition: bvh_params.h:188
__forceinline const BoundBox & bounds() const
Definition: bvh_params.h:180
__forceinline float time_from() const
Definition: bvh_params.h:196
__forceinline float time_to() const
Definition: bvh_params.h:200
__forceinline int prim_index() const
Definition: bvh_params.h:184
Transform compute_aligned_space(const BVHObjectBinning &range, const BVHReference *references) const
BoundBox compute_aligned_boundbox(const BVHObjectBinning &range, const BVHReference *references, const Transform &aligned_space, BoundBox *cent_bounds=NULL) const
BoundBox compute_aligned_prim_boundbox(const BVHReference &prim, const Transform &aligned_space) const
Type geometry_type
Definition: geometry.h:78
@ MESH
Definition: geometry.h:73
@ VOLUME
Definition: geometry.h:75
@ HAIR
Definition: geometry.h:74
bool has_motion_blur() const
Definition: geometry.cpp:255
AttributeSet attributes
Definition: geometry.h:81
BVHNode * children[kNumMaxChildren]
Definition: bvh_node.h:207
int hi
Definition: bvh_node.h:250
int lo
Definition: bvh_node.h:249
bool get_cancel()
void set_substatus(const string &substatus_)
size_t size() const
Definition: util_array.h:203
size_t capacity() const
Definition: util_array.h:257
T * resize(size_t newsize)
Definition: util_array.h:150
void reserve(size_t newcapacity)
Definition: util_array.h:244
OperationNode * node
Curve curve
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define CCL_NAMESPACE_END
#define make_float2(x, y)
#define make_float4(x, y, z, w)
#define PRIMITIVE_PACK_SEGMENT(type, segment)
Definition: kernel_types.h:710
PrimitiveType
Definition: kernel_types.h:684
@ PRIMITIVE_MOTION_CURVE_RIBBON
Definition: kernel_types.h:691
@ PRIMITIVE_ALL
Definition: kernel_types.h:702
@ PRIMITIVE_NUM_TOTAL
Definition: kernel_types.h:707
@ PRIMITIVE_MOTION_TRIANGLE
Definition: kernel_types.h:687
@ PRIMITIVE_CURVE_RIBBON
Definition: kernel_types.h:690
@ PRIMITIVE_MOTION_CURVE_THICK
Definition: kernel_types.h:689
@ PRIMITIVE_CURVE_THICK
Definition: kernel_types.h:688
@ PRIMITIVE_ALL_TRIANGLE
Definition: kernel_types.h:697
@ PRIMITIVE_ALL_CURVE
Definition: kernel_types.h:698
@ PRIMITIVE_TRIANGLE
Definition: kernel_types.h:686
@ PRIMITIVE_ALL_MOTION
Definition: kernel_types.h:700
@ ATTR_STD_MOTION_VERTEX_POSITION
Definition: kernel_types.h:756
@ CURVE_RIBBON
Definition: kernel_types.h:714
static int left
static unsigned c
Definition: RandGen.cpp:97
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
#define min(a, b)
Definition: sort.c:51
unsigned int uint32_t
Definition: stdint.h:83
int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const
Definition: bvh_node.cpp:29
void update_time()
Definition: bvh_node.cpp:140
uint update_visibility()
Definition: bvh_node.cpp:127
float time_to
Definition: bvh_node.h:113
virtual bool is_leaf() const =0
void deleteSubtree()
Definition: bvh_node.cpp:105
float time_from
Definition: bvh_node.h:113
void set_aligned_space(const Transform &aligned_space)
Definition: bvh_node.h:59
BoundBox bounds
Definition: bvh_node.h:103
__forceinline float half_area() const
__forceinline float safe_area() const
__forceinline void grow(const float3 &pt)
Definition: util_boundbox.h:55
__forceinline float3 center2() const
int num_keys
Definition: hair.h:31
Curve get_curve(size_t i) const
Definition: hair.h:119
size_t num_curves() const
Definition: hair.h:133
CurveShapeType curve_shape
Definition: hair.h:99
float size[3]
Triangle get_triangle(size_t i) const
Definition: mesh.h:86
size_t num_triangles() const
Definition: mesh.h:92
NODE_DECLARE BoundBox bounds
Definition: object.h:56
bool is_traceable() const
Definition: object.cpp:261
void push(TaskRunFunction &&task)
Definition: util_task.cpp:36
void wait_work(Summary *stats=NULL)
Definition: util_task.cpp:42
float max
__forceinline BoundBox merge(const BoundBox &bbox, const float3 &pt)
#define VLOG(severity)
Definition: util_logging.h:50
ccl_device_inline float3 zero_float3()
__forceinline uint32_t bitscan(uint32_t value)
Definition: util_simd.h:415
string string_human_readable_number(size_t num)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: util_string.cpp:32
std::unique_lock< std::mutex > thread_scoped_lock
Definition: util_thread.h:41
CCL_NAMESPACE_BEGIN double time_dt()
Definition: util_time.cpp:48