Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /intern/cycles/bvh
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'intern/cycles/bvh')
-rw-r--r--intern/cycles/bvh/CMakeLists.txt50
-rw-r--r--intern/cycles/bvh/bvh.cpp946
-rw-r--r--intern/cycles/bvh/bvh.h128
-rw-r--r--intern/cycles/bvh/bvh2.cpp458
-rw-r--r--intern/cycles/bvh/bvh2.h75
-rw-r--r--intern/cycles/bvh/bvh4.cpp688
-rw-r--r--intern/cycles/bvh/bvh4.h70
-rw-r--r--intern/cycles/bvh/bvh8.cpp852
-rw-r--r--intern/cycles/bvh/bvh8.h70
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp446
-rw-r--r--intern/cycles/bvh/bvh_binning.h149
-rw-r--r--intern/cycles/bvh/bvh_build.cpp2101
-rw-r--r--intern/cycles/bvh/bvh_build.h193
-rw-r--r--intern/cycles/bvh/bvh_embree.cpp1646
-rw-r--r--intern/cycles/bvh/bvh_embree.h103
-rw-r--r--intern/cycles/bvh/bvh_node.cpp290
-rw-r--r--intern/cycles/bvh/bvh_node.h429
-rw-r--r--intern/cycles/bvh/bvh_params.h448
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp287
-rw-r--r--intern/cycles/bvh/bvh_sort.h2
-rw-r--r--intern/cycles/bvh/bvh_split.cpp872
-rw-r--r--intern/cycles/bvh/bvh_split.h416
-rw-r--r--intern/cycles/bvh/bvh_unaligned.cpp231
-rw-r--r--intern/cycles/bvh/bvh_unaligned.h71
24 files changed, 5431 insertions, 5590 deletions
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index ea31838d816..36bbd937e1a 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -1,42 +1,42 @@
set(INC
- ..
+ ..
)
set(INC_SYS
)
set(SRC
- bvh.cpp
- bvh2.cpp
- bvh4.cpp
- bvh8.cpp
- bvh_binning.cpp
- bvh_build.cpp
- bvh_embree.cpp
- bvh_node.cpp
- bvh_sort.cpp
- bvh_split.cpp
- bvh_unaligned.cpp
+ bvh.cpp
+ bvh2.cpp
+ bvh4.cpp
+ bvh8.cpp
+ bvh_binning.cpp
+ bvh_build.cpp
+ bvh_embree.cpp
+ bvh_node.cpp
+ bvh_sort.cpp
+ bvh_split.cpp
+ bvh_unaligned.cpp
)
set(SRC_HEADERS
- bvh.h
- bvh2.h
- bvh4.h
- bvh8.h
- bvh_binning.h
- bvh_build.h
- bvh_embree.h
- bvh_node.h
- bvh_params.h
- bvh_sort.h
- bvh_split.h
- bvh_unaligned.h
+ bvh.h
+ bvh2.h
+ bvh4.h
+ bvh8.h
+ bvh_binning.h
+ bvh_build.h
+ bvh_embree.h
+ bvh_node.h
+ bvh_params.h
+ bvh_sort.h
+ bvh_split.h
+ bvh_unaligned.h
)
set(LIB
- cycles_render
+ cycles_render
)
include_directories(${INC})
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index af012bbf3ac..53c66777928 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -27,7 +27,7 @@
#include "bvh/bvh_node.h"
#ifdef WITH_EMBREE
-#include "bvh/bvh_embree.h"
+# include "bvh/bvh_embree.h"
#endif
#include "util/util_foreach.h"
@@ -40,533 +40,529 @@ CCL_NAMESPACE_BEGIN
const char *bvh_layout_name(BVHLayout layout)
{
- switch(layout) {
- case BVH_LAYOUT_BVH2: return "BVH2";
- case BVH_LAYOUT_BVH4: return "BVH4";
- case BVH_LAYOUT_BVH8: return "BVH8";
- case BVH_LAYOUT_NONE: return "NONE";
- case BVH_LAYOUT_EMBREE: return "EMBREE";
- case BVH_LAYOUT_ALL: return "ALL";
- }
- LOG(DFATAL) << "Unsupported BVH layout was passed.";
- return "";
+ switch (layout) {
+ case BVH_LAYOUT_BVH2:
+ return "BVH2";
+ case BVH_LAYOUT_BVH4:
+ return "BVH4";
+ case BVH_LAYOUT_BVH8:
+ return "BVH8";
+ case BVH_LAYOUT_NONE:
+ return "NONE";
+ case BVH_LAYOUT_EMBREE:
+ return "EMBREE";
+ case BVH_LAYOUT_ALL:
+ return "ALL";
+ }
+ LOG(DFATAL) << "Unsupported BVH layout was passed.";
+ return "";
}
-BVHLayout BVHParams::best_bvh_layout(BVHLayout requested_layout,
- BVHLayoutMask supported_layouts)
+BVHLayout BVHParams::best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask supported_layouts)
{
- const BVHLayoutMask requested_layout_mask = (BVHLayoutMask)requested_layout;
- /* Check whether requested layout is supported, if so -- no need to do
- * any extra computation.
- */
- if(supported_layouts & requested_layout_mask) {
- return requested_layout;
- }
- /* Some bit magic to get widest supported BVH layout. */
- /* This is a mask of supported BVH layouts which are narrower than the
- * requested one.
- */
- const BVHLayoutMask allowed_layouts_mask =
- (supported_layouts & (requested_layout_mask - 1));
- /* We get widest from allowed ones and convert mask to actual layout. */
- const BVHLayoutMask widest_allowed_layout_mask = __bsr(allowed_layouts_mask);
- return (BVHLayout)(1 << widest_allowed_layout_mask);
+ const BVHLayoutMask requested_layout_mask = (BVHLayoutMask)requested_layout;
+ /* Check whether requested layout is supported, if so -- no need to do
+ * any extra computation.
+ */
+ if (supported_layouts & requested_layout_mask) {
+ return requested_layout;
+ }
+ /* Some bit magic to get widest supported BVH layout. */
+ /* This is a mask of supported BVH layouts which are narrower than the
+ * requested one.
+ */
+ const BVHLayoutMask allowed_layouts_mask = (supported_layouts & (requested_layout_mask - 1));
+ /* We get widest from allowed ones and convert mask to actual layout. */
+ const BVHLayoutMask widest_allowed_layout_mask = __bsr(allowed_layouts_mask);
+ return (BVHLayout)(1 << widest_allowed_layout_mask);
}
/* Pack Utility */
-BVHStackEntry::BVHStackEntry(const BVHNode *n, int i)
- : node(n), idx(i)
+BVHStackEntry::BVHStackEntry(const BVHNode *n, int i) : node(n), idx(i)
{
}
int BVHStackEntry::encodeIdx() const
{
- return (node->is_leaf())? ~idx: idx;
+ return (node->is_leaf()) ? ~idx : idx;
}
/* BVH */
-BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
-: params(params_), objects(objects_)
+BVH::BVH(const BVHParams &params_, const vector<Object *> &objects_)
+ : params(params_), objects(objects_)
{
}
-BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
+BVH *BVH::create(const BVHParams &params, const vector<Object *> &objects)
{
- switch(params.bvh_layout) {
- case BVH_LAYOUT_BVH2:
- return new BVH2(params, objects);
- case BVH_LAYOUT_BVH4:
- return new BVH4(params, objects);
- case BVH_LAYOUT_BVH8:
- return new BVH8(params, objects);
- case BVH_LAYOUT_EMBREE:
+ switch (params.bvh_layout) {
+ case BVH_LAYOUT_BVH2:
+ return new BVH2(params, objects);
+ case BVH_LAYOUT_BVH4:
+ return new BVH4(params, objects);
+ case BVH_LAYOUT_BVH8:
+ return new BVH8(params, objects);
+ case BVH_LAYOUT_EMBREE:
#ifdef WITH_EMBREE
- return new BVHEmbree(params, objects);
+ return new BVHEmbree(params, objects);
#endif
- case BVH_LAYOUT_NONE:
- case BVH_LAYOUT_ALL:
- break;
- }
- LOG(DFATAL) << "Requested unsupported BVH layout.";
- return NULL;
+ case BVH_LAYOUT_NONE:
+ case BVH_LAYOUT_ALL:
+ break;
+ }
+ LOG(DFATAL) << "Requested unsupported BVH layout.";
+ return NULL;
}
/* Building */
-void BVH::build(Progress& progress, Stats*)
+void BVH::build(Progress &progress, Stats *)
{
- progress.set_substatus("Building BVH");
-
- /* build nodes */
- BVHBuild bvh_build(objects,
- pack.prim_type,
- pack.prim_index,
- pack.prim_object,
- pack.prim_time,
- params,
- progress);
- BVHNode *bvh2_root = bvh_build.run();
-
- if(progress.get_cancel()) {
- if(bvh2_root != NULL) {
- bvh2_root->deleteSubtree();
- }
- return;
- }
-
- /* BVH builder returns tree in a binary mode (with two children per inner
- * node. Need to adopt that for a wider BVH implementations. */
- BVHNode *root = widen_children_nodes(bvh2_root);
- if(root != bvh2_root) {
- bvh2_root->deleteSubtree();
- }
-
- if(progress.get_cancel()) {
- if(root != NULL) {
- root->deleteSubtree();
- }
- return;
- }
-
- /* pack triangles */
- progress.set_substatus("Packing BVH triangles and strands");
- pack_primitives();
-
- if(progress.get_cancel()) {
- root->deleteSubtree();
- return;
- }
-
- /* pack nodes */
- progress.set_substatus("Packing BVH nodes");
- pack_nodes(root);
-
- /* free build nodes */
- root->deleteSubtree();
+ progress.set_substatus("Building BVH");
+
+ /* build nodes */
+ BVHBuild bvh_build(objects,
+ pack.prim_type,
+ pack.prim_index,
+ pack.prim_object,
+ pack.prim_time,
+ params,
+ progress);
+ BVHNode *bvh2_root = bvh_build.run();
+
+ if (progress.get_cancel()) {
+ if (bvh2_root != NULL) {
+ bvh2_root->deleteSubtree();
+ }
+ return;
+ }
+
+ /* BVH builder returns tree in a binary mode (with two children per inner
+ * node. Need to adopt that for a wider BVH implementations. */
+ BVHNode *root = widen_children_nodes(bvh2_root);
+ if (root != bvh2_root) {
+ bvh2_root->deleteSubtree();
+ }
+
+ if (progress.get_cancel()) {
+ if (root != NULL) {
+ root->deleteSubtree();
+ }
+ return;
+ }
+
+ /* pack triangles */
+ progress.set_substatus("Packing BVH triangles and strands");
+ pack_primitives();
+
+ if (progress.get_cancel()) {
+ root->deleteSubtree();
+ return;
+ }
+
+ /* pack nodes */
+ progress.set_substatus("Packing BVH nodes");
+ pack_nodes(root);
+
+ /* free build nodes */
+ root->deleteSubtree();
}
/* Refitting */
-void BVH::refit(Progress& progress)
+void BVH::refit(Progress &progress)
{
- progress.set_substatus("Packing BVH primitives");
- pack_primitives();
+ progress.set_substatus("Packing BVH primitives");
+ pack_primitives();
- if(progress.get_cancel()) return;
+ if (progress.get_cancel())
+ return;
- progress.set_substatus("Refitting BVH nodes");
- refit_nodes();
+ progress.set_substatus("Refitting BVH nodes");
+ refit_nodes();
}
-void BVH::refit_primitives(int start, int end, BoundBox& bbox, uint& visibility)
+void BVH::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility)
{
- /* Refit range of primitives. */
- for(int prim = start; prim < end; prim++) {
- int pidx = pack.prim_index[prim];
- int tob = pack.prim_object[prim];
- Object *ob = objects[tob];
-
- if(pidx == -1) {
- /* Object instance. */
- bbox.grow(ob->bounds);
- }
- else {
- /* Primitives. */
- const Mesh *mesh = ob->mesh;
-
- if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
- /* Curves. */
- int str_offset = (params.top_level)? mesh->curve_offset: 0;
- Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
- int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
-
- curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
-
- visibility |= PATH_RAY_CURVE;
-
- /* Motion curves. */
- if(mesh->use_motion_blur) {
- Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if(attr) {
- size_t mesh_size = mesh->curve_keys.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *key_steps = attr->data_float3();
-
- for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
- }
- }
- }
- else {
- /* Triangles. */
- int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
- const float3 *vpos = &mesh->verts[0];
-
- triangle.bounds_grow(vpos, bbox);
-
- /* Motion triangles. */
- if(mesh->use_motion_blur) {
- Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if(attr) {
- size_t mesh_size = mesh->verts.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *vert_steps = attr->data_float3();
-
- for(size_t i = 0; i < steps; i++)
- triangle.bounds_grow(vert_steps + i*mesh_size, bbox);
- }
- }
- }
- }
- visibility |= ob->visibility_for_tracing();
-
- }
+ /* Refit range of primitives. */
+ for (int prim = start; prim < end; prim++) {
+ int pidx = pack.prim_index[prim];
+ int tob = pack.prim_object[prim];
+ Object *ob = objects[tob];
+
+ if (pidx == -1) {
+ /* Object instance. */
+ bbox.grow(ob->bounds);
+ }
+ else {
+ /* Primitives. */
+ const Mesh *mesh = ob->mesh;
+
+ if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
+ /* Curves. */
+ int str_offset = (params.top_level) ? mesh->curve_offset : 0;
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
+ int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
+
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
+
+ visibility |= PATH_RAY_CURVE;
+
+ /* Motion curves. */
+ if (mesh->use_motion_blur) {
+ Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t mesh_size = mesh->curve_keys.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *key_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ curve.bounds_grow(k, key_steps + i * mesh_size, &mesh->curve_radius[0], bbox);
+ }
+ }
+ }
+ else {
+ /* Triangles. */
+ int tri_offset = (params.top_level) ? mesh->tri_offset : 0;
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
+ const float3 *vpos = &mesh->verts[0];
+
+ triangle.bounds_grow(vpos, bbox);
+
+ /* Motion triangles. */
+ if (mesh->use_motion_blur) {
+ Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t mesh_size = mesh->verts.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ triangle.bounds_grow(vert_steps + i * mesh_size, bbox);
+ }
+ }
+ }
+ }
+ visibility |= ob->visibility_for_tracing();
+ }
}
/* Triangles */
void BVH::pack_triangle(int idx, float4 tri_verts[3])
{
- int tob = pack.prim_object[idx];
- assert(tob >= 0 && tob < objects.size());
- const Mesh *mesh = objects[tob]->mesh;
-
- int tidx = pack.prim_index[idx];
- Mesh::Triangle t = mesh->get_triangle(tidx);
- const float3 *vpos = &mesh->verts[0];
- float3 v0 = vpos[t.v[0]];
- float3 v1 = vpos[t.v[1]];
- float3 v2 = vpos[t.v[2]];
-
- tri_verts[0] = float3_to_float4(v0);
- tri_verts[1] = float3_to_float4(v1);
- tri_verts[2] = float3_to_float4(v2);
+ int tob = pack.prim_object[idx];
+ assert(tob >= 0 && tob < objects.size());
+ const Mesh *mesh = objects[tob]->mesh;
+
+ int tidx = pack.prim_index[idx];
+ Mesh::Triangle t = mesh->get_triangle(tidx);
+ const float3 *vpos = &mesh->verts[0];
+ float3 v0 = vpos[t.v[0]];
+ float3 v1 = vpos[t.v[1]];
+ float3 v2 = vpos[t.v[2]];
+
+ tri_verts[0] = float3_to_float4(v0);
+ tri_verts[1] = float3_to_float4(v1);
+ tri_verts[2] = float3_to_float4(v2);
}
void BVH::pack_primitives()
{
- const size_t tidx_size = pack.prim_index.size();
- size_t num_prim_triangles = 0;
- /* Count number of triangles primitives in BVH. */
- for(unsigned int i = 0; i < tidx_size; i++) {
- if((pack.prim_index[i] != -1)) {
- if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- ++num_prim_triangles;
- }
- }
- }
- /* Reserve size for arrays. */
- pack.prim_tri_index.clear();
- pack.prim_tri_index.resize(tidx_size);
- pack.prim_tri_verts.clear();
- pack.prim_tri_verts.resize(num_prim_triangles * 3);
- pack.prim_visibility.clear();
- pack.prim_visibility.resize(tidx_size);
- /* Fill in all the arrays. */
- size_t prim_triangle_index = 0;
- for(unsigned int i = 0; i < tidx_size; i++) {
- if(pack.prim_index[i] != -1) {
- int tob = pack.prim_object[i];
- Object *ob = objects[tob];
- if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]);
- pack.prim_tri_index[i] = 3 * prim_triangle_index;
- ++prim_triangle_index;
- }
- else {
- pack.prim_tri_index[i] = -1;
- }
- pack.prim_visibility[i] = ob->visibility_for_tracing();
- if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack.prim_visibility[i] |= PATH_RAY_CURVE;
- }
- }
- else {
- pack.prim_tri_index[i] = -1;
- pack.prim_visibility[i] = 0;
- }
- }
+ const size_t tidx_size = pack.prim_index.size();
+ size_t num_prim_triangles = 0;
+ /* Count number of triangles primitives in BVH. */
+ for (unsigned int i = 0; i < tidx_size; i++) {
+ if ((pack.prim_index[i] != -1)) {
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ ++num_prim_triangles;
+ }
+ }
+ }
+ /* Reserve size for arrays. */
+ pack.prim_tri_index.clear();
+ pack.prim_tri_index.resize(tidx_size);
+ pack.prim_tri_verts.clear();
+ pack.prim_tri_verts.resize(num_prim_triangles * 3);
+ pack.prim_visibility.clear();
+ pack.prim_visibility.resize(tidx_size);
+ /* Fill in all the arrays. */
+ size_t prim_triangle_index = 0;
+ for (unsigned int i = 0; i < tidx_size; i++) {
+ if (pack.prim_index[i] != -1) {
+ int tob = pack.prim_object[i];
+ Object *ob = objects[tob];
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ pack_triangle(i, (float4 *)&pack.prim_tri_verts[3 * prim_triangle_index]);
+ pack.prim_tri_index[i] = 3 * prim_triangle_index;
+ ++prim_triangle_index;
+ }
+ else {
+ pack.prim_tri_index[i] = -1;
+ }
+ pack.prim_visibility[i] = ob->visibility_for_tracing();
+ if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+ pack.prim_visibility[i] |= PATH_RAY_CURVE;
+ }
+ }
+ else {
+ pack.prim_tri_index[i] = -1;
+ pack.prim_visibility[i] = 0;
+ }
+ }
}
/* Pack Instances */
void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
{
- /* The BVH's for instances are built separately, but for traversal all
- * BVH's are stored in global arrays. This function merges them into the
- * top level BVH, adjusting indexes and offsets where appropriate.
- */
- const bool use_qbvh = (params.bvh_layout == BVH_LAYOUT_BVH4);
- const bool use_obvh = (params.bvh_layout == BVH_LAYOUT_BVH8);
-
- /* Adjust primitive index to point to the triangle in the global array, for
- * meshes with transform applied and already in the top level BVH.
- */
- for(size_t i = 0; i < pack.prim_index.size(); i++)
- if(pack.prim_index[i] != -1) {
- if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
- pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
- else
- pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
- }
-
- /* track offsets of instanced BVH data in global array */
- size_t prim_offset = pack.prim_index.size();
- size_t nodes_offset = nodes_size;
- size_t nodes_leaf_offset = leaf_nodes_size;
-
- /* clear array that gives the node indexes for instanced objects */
- pack.object_node.clear();
-
- /* reserve */
- size_t prim_index_size = pack.prim_index.size();
- size_t prim_tri_verts_size = pack.prim_tri_verts.size();
-
- size_t pack_prim_index_offset = prim_index_size;
- size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
- size_t pack_nodes_offset = nodes_size;
- size_t pack_leaf_nodes_offset = leaf_nodes_size;
- size_t object_offset = 0;
-
- map<Mesh*, int> mesh_map;
-
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
- BVH *bvh = mesh->bvh;
-
- if(mesh->need_build_bvh()) {
- if(mesh_map.find(mesh) == mesh_map.end()) {
- prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
- nodes_size += bvh->pack.nodes.size();
- leaf_nodes_size += bvh->pack.leaf_nodes.size();
-
- mesh_map[mesh] = 1;
- }
- }
- }
-
- mesh_map.clear();
-
- pack.prim_index.resize(prim_index_size);
- pack.prim_type.resize(prim_index_size);
- pack.prim_object.resize(prim_index_size);
- pack.prim_visibility.resize(prim_index_size);
- pack.prim_tri_verts.resize(prim_tri_verts_size);
- pack.prim_tri_index.resize(prim_index_size);
- pack.nodes.resize(nodes_size);
- pack.leaf_nodes.resize(leaf_nodes_size);
- pack.object_node.resize(objects.size());
-
- if(params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
- pack.prim_time.resize(prim_index_size);
- }
-
- int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
- int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
- int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
- uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
- float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL;
- uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL;
- int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
- int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL;
- float2 *pack_prim_time = (pack.prim_time.size())? &pack.prim_time[0]: NULL;
-
- /* merge */
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
-
- /* We assume that if mesh doesn't need own BVH it was already included
- * into a top-level BVH and no packing here is needed.
- */
- if(!mesh->need_build_bvh()) {
- pack.object_node[object_offset++] = 0;
- continue;
- }
-
- /* if mesh already added once, don't add it again, but used set
- * node offset for this object */
- map<Mesh*, int>::iterator it = mesh_map.find(mesh);
-
- if(mesh_map.find(mesh) != mesh_map.end()) {
- int noffset = it->second;
- pack.object_node[object_offset++] = noffset;
- continue;
- }
-
- BVH *bvh = mesh->bvh;
-
- int noffset = nodes_offset;
- int noffset_leaf = nodes_leaf_offset;
- int mesh_tri_offset = mesh->tri_offset;
- int mesh_curve_offset = mesh->curve_offset;
-
- /* fill in node indexes for instances */
- if(bvh->pack.root_index == -1)
- pack.object_node[object_offset++] = -noffset_leaf-1;
- else
- pack.object_node[object_offset++] = noffset;
-
- mesh_map[mesh] = pack.object_node[object_offset-1];
-
- /* merge primitive, object and triangle indexes */
- if(bvh->pack.prim_index.size()) {
- size_t bvh_prim_index_size = bvh->pack.prim_index.size();
- int *bvh_prim_index = &bvh->pack.prim_index[0];
- int *bvh_prim_type = &bvh->pack.prim_type[0];
- uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
- uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
- float2 *bvh_prim_time = bvh->pack.prim_time.size()? &bvh->pack.prim_time[0]: NULL;
-
- for(size_t i = 0; i < bvh_prim_index_size; i++) {
- if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
- pack_prim_tri_index[pack_prim_index_offset] = -1;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
- pack_prim_tri_index[pack_prim_index_offset] =
- bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
- }
-
- pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
- pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
- pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
- if(bvh_prim_time != NULL) {
- pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i];
- }
- pack_prim_index_offset++;
- }
- }
-
- /* Merge triangle vertices data. */
- if(bvh->pack.prim_tri_verts.size()) {
- const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
- memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
- &bvh->pack.prim_tri_verts[0],
- prim_tri_size*sizeof(float4));
- pack_prim_tri_verts_offset += prim_tri_size;
- }
-
- /* merge nodes */
- if(bvh->pack.leaf_nodes.size()) {
- int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
- size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
- for(size_t i = 0, j = 0;
- i < leaf_nodes_offset_size;
- i += BVH_NODE_LEAF_SIZE, j++)
- {
- int4 data = leaf_nodes_offset[i];
- data.x += prim_offset;
- data.y += prim_offset;
- pack_leaf_nodes[pack_leaf_nodes_offset] = data;
- for(int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
- pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
- }
- pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
- }
- }
-
- if(bvh->pack.nodes.size()) {
- int4 *bvh_nodes = &bvh->pack.nodes[0];
- size_t bvh_nodes_size = bvh->pack.nodes.size();
-
- for(size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
- size_t nsize, nsize_bbox;
- if(bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
- if(use_obvh) {
- nsize = BVH_UNALIGNED_ONODE_SIZE;
- nsize_bbox = BVH_UNALIGNED_ONODE_SIZE-1;
- }
- else {
- nsize = use_qbvh
- ? BVH_UNALIGNED_QNODE_SIZE
- : BVH_UNALIGNED_NODE_SIZE;
- nsize_bbox = (use_qbvh) ? BVH_UNALIGNED_QNODE_SIZE-1 : 0;
- }
- }
- else {
- if(use_obvh) {
- nsize = BVH_ONODE_SIZE;
- nsize_bbox = BVH_ONODE_SIZE-1;
- }
- else {
- nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
- nsize_bbox = (use_qbvh)? BVH_QNODE_SIZE-1 : 0;
- }
- }
-
- memcpy(pack_nodes + pack_nodes_offset,
- bvh_nodes + i,
- nsize_bbox*sizeof(int4));
-
- /* Modify offsets into arrays */
- int4 data = bvh_nodes[i + nsize_bbox];
- int4 data1 = bvh_nodes[i + nsize_bbox-1];
- if(use_obvh) {
- data.z += (data.z < 0) ? -noffset_leaf : noffset;
- data.w += (data.w < 0) ? -noffset_leaf : noffset;
- data.x += (data.x < 0) ? -noffset_leaf : noffset;
- data.y += (data.y < 0) ? -noffset_leaf : noffset;
- data1.z += (data1.z < 0) ? -noffset_leaf : noffset;
- data1.w += (data1.w < 0) ? -noffset_leaf : noffset;
- data1.x += (data1.x < 0) ? -noffset_leaf : noffset;
- data1.y += (data1.y < 0) ? -noffset_leaf : noffset;
- }
- else {
- data.z += (data.z < 0) ? -noffset_leaf : noffset;
- data.w += (data.w < 0) ? -noffset_leaf : noffset;
- if(use_qbvh) {
- data.x += (data.x < 0)? -noffset_leaf: noffset;
- data.y += (data.y < 0)? -noffset_leaf: noffset;
- }
- }
- pack_nodes[pack_nodes_offset + nsize_bbox] = data;
- if(use_obvh) {
- pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1;
- }
-
- /* Usually this copies nothing, but we better
- * be prepared for possible node size extension.
- */
- memcpy(&pack_nodes[pack_nodes_offset + nsize_bbox+1],
- &bvh_nodes[i + nsize_bbox+1],
- sizeof(int4) * (nsize - (nsize_bbox+1)));
-
- pack_nodes_offset += nsize;
- i += nsize;
- }
- }
-
- nodes_offset += bvh->pack.nodes.size();
- nodes_leaf_offset += bvh->pack.leaf_nodes.size();
- prim_offset += bvh->pack.prim_index.size();
- }
+ /* The BVH's for instances are built separately, but for traversal all
+ * BVH's are stored in global arrays. This function merges them into the
+ * top level BVH, adjusting indexes and offsets where appropriate.
+ */
+ const bool use_qbvh = (params.bvh_layout == BVH_LAYOUT_BVH4);
+ const bool use_obvh = (params.bvh_layout == BVH_LAYOUT_BVH8);
+
+ /* Adjust primitive index to point to the triangle in the global array, for
+ * meshes with transform applied and already in the top level BVH.
+ */
+ for (size_t i = 0; i < pack.prim_index.size(); i++)
+ if (pack.prim_index[i] != -1) {
+ if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
+ else
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+ }
+
+ /* track offsets of instanced BVH data in global array */
+ size_t prim_offset = pack.prim_index.size();
+ size_t nodes_offset = nodes_size;
+ size_t nodes_leaf_offset = leaf_nodes_size;
+
+ /* clear array that gives the node indexes for instanced objects */
+ pack.object_node.clear();
+
+ /* reserve */
+ size_t prim_index_size = pack.prim_index.size();
+ size_t prim_tri_verts_size = pack.prim_tri_verts.size();
+
+ size_t pack_prim_index_offset = prim_index_size;
+ size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
+ size_t pack_nodes_offset = nodes_size;
+ size_t pack_leaf_nodes_offset = leaf_nodes_size;
+ size_t object_offset = 0;
+
+ map<Mesh *, int> mesh_map;
+
+ foreach (Object *ob, objects) {
+ Mesh *mesh = ob->mesh;
+ BVH *bvh = mesh->bvh;
+
+ if (mesh->need_build_bvh()) {
+ if (mesh_map.find(mesh) == mesh_map.end()) {
+ prim_index_size += bvh->pack.prim_index.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+ nodes_size += bvh->pack.nodes.size();
+ leaf_nodes_size += bvh->pack.leaf_nodes.size();
+
+ mesh_map[mesh] = 1;
+ }
+ }
+ }
+
+ mesh_map.clear();
+
+ pack.prim_index.resize(prim_index_size);
+ pack.prim_type.resize(prim_index_size);
+ pack.prim_object.resize(prim_index_size);
+ pack.prim_visibility.resize(prim_index_size);
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ pack.prim_tri_index.resize(prim_index_size);
+ pack.nodes.resize(nodes_size);
+ pack.leaf_nodes.resize(leaf_nodes_size);
+ pack.object_node.resize(objects.size());
+
+ if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
+ pack.prim_time.resize(prim_index_size);
+ }
+
+ int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : NULL;
+ int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
+ int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
+ uint *pack_prim_visibility = (pack.prim_visibility.size()) ? &pack.prim_visibility[0] : NULL;
+ float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
+ uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
+ int4 *pack_nodes = (pack.nodes.size()) ? &pack.nodes[0] : NULL;
+ int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
+ float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
+
+ /* merge */
+ foreach (Object *ob, objects) {
+ Mesh *mesh = ob->mesh;
+
+ /* We assume that if mesh doesn't need own BVH it was already included
+ * into a top-level BVH and no packing here is needed.
+ */
+ if (!mesh->need_build_bvh()) {
+ pack.object_node[object_offset++] = 0;
+ continue;
+ }
+
+ /* if mesh already added once, don't add it again, but used set
+ * node offset for this object */
+ map<Mesh *, int>::iterator it = mesh_map.find(mesh);
+
+ if (mesh_map.find(mesh) != mesh_map.end()) {
+ int noffset = it->second;
+ pack.object_node[object_offset++] = noffset;
+ continue;
+ }
+
+ BVH *bvh = mesh->bvh;
+
+ int noffset = nodes_offset;
+ int noffset_leaf = nodes_leaf_offset;
+ int mesh_tri_offset = mesh->tri_offset;
+ int mesh_curve_offset = mesh->curve_offset;
+
+ /* fill in node indexes for instances */
+ if (bvh->pack.root_index == -1)
+ pack.object_node[object_offset++] = -noffset_leaf - 1;
+ else
+ pack.object_node[object_offset++] = noffset;
+
+ mesh_map[mesh] = pack.object_node[object_offset - 1];
+
+ /* merge primitive, object and triangle indexes */
+ if (bvh->pack.prim_index.size()) {
+ size_t bvh_prim_index_size = bvh->pack.prim_index.size();
+ int *bvh_prim_index = &bvh->pack.prim_index[0];
+ int *bvh_prim_type = &bvh->pack.prim_type[0];
+ uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
+ uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
+ float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
+
+ for (size_t i = 0; i < bvh_prim_index_size; i++) {
+ if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = -1;
+ }
+ else {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
+ pack_prim_tri_verts_offset;
+ }
+
+ pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
+ pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
+ pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
+ if (bvh_prim_time != NULL) {
+ pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i];
+ }
+ pack_prim_index_offset++;
+ }
+ }
+
+ /* Merge triangle vertices data. */
+ if (bvh->pack.prim_tri_verts.size()) {
+ const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+ &bvh->pack.prim_tri_verts[0],
+ prim_tri_size * sizeof(float4));
+ pack_prim_tri_verts_offset += prim_tri_size;
+ }
+
+ /* merge nodes */
+ if (bvh->pack.leaf_nodes.size()) {
+ int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
+ size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
+ for (size_t i = 0, j = 0; i < leaf_nodes_offset_size; i += BVH_NODE_LEAF_SIZE, j++) {
+ int4 data = leaf_nodes_offset[i];
+ data.x += prim_offset;
+ data.y += prim_offset;
+ pack_leaf_nodes[pack_leaf_nodes_offset] = data;
+ for (int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
+ pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
+ }
+ pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
+ }
+ }
+
+ if (bvh->pack.nodes.size()) {
+ int4 *bvh_nodes = &bvh->pack.nodes[0];
+ size_t bvh_nodes_size = bvh->pack.nodes.size();
+
+ for (size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
+ size_t nsize, nsize_bbox;
+ if (bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
+ if (use_obvh) {
+ nsize = BVH_UNALIGNED_ONODE_SIZE;
+ nsize_bbox = BVH_UNALIGNED_ONODE_SIZE - 1;
+ }
+ else {
+ nsize = use_qbvh ? BVH_UNALIGNED_QNODE_SIZE : BVH_UNALIGNED_NODE_SIZE;
+ nsize_bbox = (use_qbvh) ? BVH_UNALIGNED_QNODE_SIZE - 1 : 0;
+ }
+ }
+ else {
+ if (use_obvh) {
+ nsize = BVH_ONODE_SIZE;
+ nsize_bbox = BVH_ONODE_SIZE - 1;
+ }
+ else {
+ nsize = (use_qbvh) ? BVH_QNODE_SIZE : BVH_NODE_SIZE;
+ nsize_bbox = (use_qbvh) ? BVH_QNODE_SIZE - 1 : 0;
+ }
+ }
+
+ memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox * sizeof(int4));
+
+ /* Modify offsets into arrays */
+ int4 data = bvh_nodes[i + nsize_bbox];
+ int4 data1 = bvh_nodes[i + nsize_bbox - 1];
+ if (use_obvh) {
+ data.z += (data.z < 0) ? -noffset_leaf : noffset;
+ data.w += (data.w < 0) ? -noffset_leaf : noffset;
+ data.x += (data.x < 0) ? -noffset_leaf : noffset;
+ data.y += (data.y < 0) ? -noffset_leaf : noffset;
+ data1.z += (data1.z < 0) ? -noffset_leaf : noffset;
+ data1.w += (data1.w < 0) ? -noffset_leaf : noffset;
+ data1.x += (data1.x < 0) ? -noffset_leaf : noffset;
+ data1.y += (data1.y < 0) ? -noffset_leaf : noffset;
+ }
+ else {
+ data.z += (data.z < 0) ? -noffset_leaf : noffset;
+ data.w += (data.w < 0) ? -noffset_leaf : noffset;
+ if (use_qbvh) {
+ data.x += (data.x < 0) ? -noffset_leaf : noffset;
+ data.y += (data.y < 0) ? -noffset_leaf : noffset;
+ }
+ }
+ pack_nodes[pack_nodes_offset + nsize_bbox] = data;
+ if (use_obvh) {
+ pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1;
+ }
+
+ /* Usually this copies nothing, but we better
+ * be prepared for possible node size extension.
+ */
+ memcpy(&pack_nodes[pack_nodes_offset + nsize_bbox + 1],
+ &bvh_nodes[i + nsize_bbox + 1],
+ sizeof(int4) * (nsize - (nsize_bbox + 1)));
+
+ pack_nodes_offset += nsize;
+ i += nsize;
+ }
+ }
+
+ nodes_offset += bvh->pack.nodes.size();
+ nodes_leaf_offset += bvh->pack.leaf_nodes.size();
+ prim_offset += bvh->pack.prim_index.size();
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 33a069eeaf5..edce3ca6f2a 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -34,96 +34,92 @@ class LeafNode;
class Object;
class Progress;
-#define BVH_ALIGN 4096
+#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
/* Packed BVH
*
* BVH stored as it will be used for traversal on the rendering device. */
struct PackedBVH {
- /* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
- * and child, triangle or object indexes depending on the node type */
- array<int4> nodes;
- /* BVH leaf nodes storage. */
- array<int4> leaf_nodes;
- /* object index to BVH node index mapping for instances */
- array<int> object_node;
- /* Mapping from primitive index to index in triangle array. */
- array<uint> prim_tri_index;
- /* Continuous storage of triangle vertices. */
- array<float4> prim_tri_verts;
- /* primitive type - triangle or strand */
- array<int> prim_type;
- /* visibility visibilitys for primitives */
- array<uint> prim_visibility;
- /* mapping from BVH primitive index to true primitive index, as primitives
- * may be duplicated due to spatial splits. -1 for instances. */
- array<int> prim_index;
- /* mapping from BVH primitive index, to the object id of that primitive. */
- array<int> prim_object;
- /* Time range of BVH primitive. */
- array<float2> prim_time;
-
- /* index of the root node. */
- int root_index;
-
- PackedBVH()
- {
- root_index = 0;
- }
+ /* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
+ * and child, triangle or object indexes depending on the node type */
+ array<int4> nodes;
+ /* BVH leaf nodes storage. */
+ array<int4> leaf_nodes;
+ /* object index to BVH node index mapping for instances */
+ array<int> object_node;
+ /* Mapping from primitive index to index in triangle array. */
+ array<uint> prim_tri_index;
+ /* Continuous storage of triangle vertices. */
+ array<float4> prim_tri_verts;
+ /* primitive type - triangle or strand */
+ array<int> prim_type;
+ /* visibility visibilitys for primitives */
+ array<uint> prim_visibility;
+ /* mapping from BVH primitive index to true primitive index, as primitives
+ * may be duplicated due to spatial splits. -1 for instances. */
+ array<int> prim_index;
+ /* mapping from BVH primitive index, to the object id of that primitive. */
+ array<int> prim_object;
+ /* Time range of BVH primitive. */
+ array<float2> prim_time;
+
+ /* index of the root node. */
+ int root_index;
+
+ PackedBVH()
+ {
+ root_index = 0;
+ }
};
-enum BVH_TYPE {
- bvh2,
- bvh4,
- bvh8
-};
+enum BVH_TYPE { bvh2, bvh4, bvh8 };
/* BVH */
-class BVH
-{
-public:
- PackedBVH pack;
- BVHParams params;
- vector<Object*> objects;
+class BVH {
+ public:
+ PackedBVH pack;
+ BVHParams params;
+ vector<Object *> objects;
- static BVH *create(const BVHParams& params, const vector<Object*>& objects);
- virtual ~BVH() {}
+ static BVH *create(const BVHParams &params, const vector<Object *> &objects);
+ virtual ~BVH()
+ {
+ }
- virtual void build(Progress& progress, Stats *stats=NULL);
- void refit(Progress& progress);
+ virtual void build(Progress &progress, Stats *stats = NULL);
+ void refit(Progress &progress);
-protected:
- BVH(const BVHParams& params, const vector<Object*>& objects);
+ protected:
+ BVH(const BVHParams &params, const vector<Object *> &objects);
- /* Refit range of primitives. */
- void refit_primitives(int start, int end, BoundBox& bbox, uint& visibility);
+ /* Refit range of primitives. */
+ void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility);
- /* triangles and strands */
- void pack_primitives();
- void pack_triangle(int idx, float4 storage[3]);
+ /* triangles and strands */
+ void pack_primitives();
+ void pack_triangle(int idx, float4 storage[3]);
- /* merge instance BVH's */
- void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
+ /* merge instance BVH's */
+ void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
- /* for subclasses to implement */
- virtual void pack_nodes(const BVHNode *root) = 0;
- virtual void refit_nodes() = 0;
+ /* for subclasses to implement */
+ virtual void pack_nodes(const BVHNode *root) = 0;
+ virtual void refit_nodes() = 0;
- virtual BVHNode *widen_children_nodes(const BVHNode *root) = 0;
+ virtual BVHNode *widen_children_nodes(const BVHNode *root) = 0;
};
/* Pack Utility */
-struct BVHStackEntry
-{
- const BVHNode *node;
- int idx;
+struct BVHStackEntry {
+ const BVHNode *node;
+ int idx;
- BVHStackEntry(const BVHNode *n = 0, int i = 0);
- int encodeIdx() const;
+ BVHStackEntry(const BVHNode *n = 0, int i = 0);
+ int encodeIdx() const;
};
CCL_NAMESPACE_END
-#endif /* __BVH_H__ */
+#endif /* __BVH_H__ */
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index e5dc4e6b1a8..f419d413ef6 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -25,276 +25,268 @@
CCL_NAMESPACE_BEGIN
-BVH2::BVH2(const BVHParams& params_, const vector<Object*>& objects_)
-: BVH(params_, objects_)
+BVH2::BVH2(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
{
}
BVHNode *BVH2::widen_children_nodes(const BVHNode *root)
{
- return const_cast<BVHNode *>(root);
+ return const_cast<BVHNode *>(root);
}
-void BVH2::pack_leaf(const BVHStackEntry& e,
- const LeafNode *leaf)
+void BVH2::pack_leaf(const BVHStackEntry &e, const LeafNode *leaf)
{
- assert(e.idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
- float4 data[BVH_NODE_LEAF_SIZE];
- memset(data, 0, sizeof(data));
- if(leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
- /* object */
- data[0].x = __int_as_float(~(leaf->lo));
- data[0].y = __int_as_float(0);
- }
- else {
- /* triangle */
- data[0].x = __int_as_float(leaf->lo);
- data[0].y = __int_as_float(leaf->hi);
- }
- data[0].z = __uint_as_float(leaf->visibility);
- if(leaf->num_triangles() != 0) {
- data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
- }
-
- memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
+ assert(e.idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
+ float4 data[BVH_NODE_LEAF_SIZE];
+ memset(data, 0, sizeof(data));
+ if (leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
+ /* object */
+ data[0].x = __int_as_float(~(leaf->lo));
+ data[0].y = __int_as_float(0);
+ }
+ else {
+ /* triangle */
+ data[0].x = __int_as_float(leaf->lo);
+ data[0].y = __int_as_float(leaf->hi);
+ }
+ data[0].z = __uint_as_float(leaf->visibility);
+ if (leaf->num_triangles() != 0) {
+ data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
+ }
+
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4) * BVH_NODE_LEAF_SIZE);
}
-void BVH2::pack_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1)
+void BVH2::pack_inner(const BVHStackEntry &e, const BVHStackEntry &e0, const BVHStackEntry &e1)
{
- if(e0.node->is_unaligned || e1.node->is_unaligned) {
- pack_unaligned_inner(e, e0, e1);
- } else {
- pack_aligned_inner(e, e0, e1);
- }
+ if (e0.node->is_unaligned || e1.node->is_unaligned) {
+ pack_unaligned_inner(e, e0, e1);
+ }
+ else {
+ pack_aligned_inner(e, e0, e1);
+ }
}
-void BVH2::pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1)
+void BVH2::pack_aligned_inner(const BVHStackEntry &e,
+ const BVHStackEntry &e0,
+ const BVHStackEntry &e1)
{
- pack_aligned_node(e.idx,
- e0.node->bounds, e1.node->bounds,
- e0.encodeIdx(), e1.encodeIdx(),
- e0.node->visibility, e1.node->visibility);
+ pack_aligned_node(e.idx,
+ e0.node->bounds,
+ e1.node->bounds,
+ e0.encodeIdx(),
+ e1.encodeIdx(),
+ e0.node->visibility,
+ e1.node->visibility);
}
void BVH2::pack_aligned_node(int idx,
- const BoundBox& b0,
- const BoundBox& b1,
- int c0, int c1,
- uint visibility0, uint visibility1)
+ const BoundBox &b0,
+ const BoundBox &b1,
+ int c0,
+ int c1,
+ uint visibility0,
+ uint visibility1)
{
- assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
- assert(c0 < 0 || c0 < pack.nodes.size());
- assert(c1 < 0 || c1 < pack.nodes.size());
-
- int4 data[BVH_NODE_SIZE] = {
- make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED,
- visibility1 & ~PATH_RAY_NODE_UNALIGNED,
- c0, c1),
- make_int4(__float_as_int(b0.min.x),
- __float_as_int(b1.min.x),
- __float_as_int(b0.max.x),
- __float_as_int(b1.max.x)),
- make_int4(__float_as_int(b0.min.y),
- __float_as_int(b1.min.y),
- __float_as_int(b0.max.y),
- __float_as_int(b1.max.y)),
- make_int4(__float_as_int(b0.min.z),
- __float_as_int(b1.min.z),
- __float_as_int(b0.max.z),
- __float_as_int(b1.max.z)),
- };
-
- memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE);
+ assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
+ assert(c0 < 0 || c0 < pack.nodes.size());
+ assert(c1 < 0 || c1 < pack.nodes.size());
+
+ int4 data[BVH_NODE_SIZE] = {
+ make_int4(
+ visibility0 & ~PATH_RAY_NODE_UNALIGNED, visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1),
+ make_int4(__float_as_int(b0.min.x),
+ __float_as_int(b1.min.x),
+ __float_as_int(b0.max.x),
+ __float_as_int(b1.max.x)),
+ make_int4(__float_as_int(b0.min.y),
+ __float_as_int(b1.min.y),
+ __float_as_int(b0.max.y),
+ __float_as_int(b1.max.y)),
+ make_int4(__float_as_int(b0.min.z),
+ __float_as_int(b1.min.z),
+ __float_as_int(b0.max.z),
+ __float_as_int(b1.max.z)),
+ };
+
+ memcpy(&pack.nodes[idx], data, sizeof(int4) * BVH_NODE_SIZE);
}
-void BVH2::pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1)
+void BVH2::pack_unaligned_inner(const BVHStackEntry &e,
+ const BVHStackEntry &e0,
+ const BVHStackEntry &e1)
{
- pack_unaligned_node(e.idx,
- e0.node->get_aligned_space(),
- e1.node->get_aligned_space(),
- e0.node->bounds,
- e1.node->bounds,
- e0.encodeIdx(), e1.encodeIdx(),
- e0.node->visibility, e1.node->visibility);
+ pack_unaligned_node(e.idx,
+ e0.node->get_aligned_space(),
+ e1.node->get_aligned_space(),
+ e0.node->bounds,
+ e1.node->bounds,
+ e0.encodeIdx(),
+ e1.encodeIdx(),
+ e0.node->visibility,
+ e1.node->visibility);
}
void BVH2::pack_unaligned_node(int idx,
- const Transform& aligned_space0,
- const Transform& aligned_space1,
- const BoundBox& bounds0,
- const BoundBox& bounds1,
- int c0, int c1,
- uint visibility0, uint visibility1)
+ const Transform &aligned_space0,
+ const Transform &aligned_space1,
+ const BoundBox &bounds0,
+ const BoundBox &bounds1,
+ int c0,
+ int c1,
+ uint visibility0,
+ uint visibility1)
{
- assert(idx + BVH_UNALIGNED_NODE_SIZE <= pack.nodes.size());
- assert(c0 < 0 || c0 < pack.nodes.size());
- assert(c1 < 0 || c1 < pack.nodes.size());
-
- float4 data[BVH_UNALIGNED_NODE_SIZE];
- Transform space0 = BVHUnaligned::compute_node_transform(bounds0,
- aligned_space0);
- Transform space1 = BVHUnaligned::compute_node_transform(bounds1,
- aligned_space1);
- data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED),
- __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED),
- __int_as_float(c0),
- __int_as_float(c1));
-
- data[1] = space0.x;
- data[2] = space0.y;
- data[3] = space0.z;
- data[4] = space1.x;
- data[5] = space1.y;
- data[6] = space1.z;
-
- memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE);
+ assert(idx + BVH_UNALIGNED_NODE_SIZE <= pack.nodes.size());
+ assert(c0 < 0 || c0 < pack.nodes.size());
+ assert(c1 < 0 || c1 < pack.nodes.size());
+
+ float4 data[BVH_UNALIGNED_NODE_SIZE];
+ Transform space0 = BVHUnaligned::compute_node_transform(bounds0, aligned_space0);
+ Transform space1 = BVHUnaligned::compute_node_transform(bounds1, aligned_space1);
+ data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(c0),
+ __int_as_float(c1));
+
+ data[1] = space0.x;
+ data[2] = space0.y;
+ data[3] = space0.z;
+ data[4] = space1.x;
+ data[5] = space1.y;
+ data[6] = space1.z;
+
+ memcpy(&pack.nodes[idx], data, sizeof(float4) * BVH_UNALIGNED_NODE_SIZE);
}
void BVH2::pack_nodes(const BVHNode *root)
{
- const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
- const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- assert(num_leaf_nodes <= num_nodes);
- const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
- size_t node_size;
- if(params.use_unaligned_nodes) {
- const size_t num_unaligned_nodes =
- root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
- node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) +
- (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE;
- }
- else {
- node_size = num_inner_nodes * BVH_NODE_SIZE;
- }
- /* Resize arrays */
- pack.nodes.clear();
- pack.leaf_nodes.clear();
- /* For top level BVH, first merge existing BVH's so we know the offsets. */
- if(params.top_level) {
- pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE);
- }
- else {
- pack.nodes.resize(node_size);
- pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE);
- }
-
- int nextNodeIdx = 0, nextLeafNodeIdx = 0;
-
- vector<BVHStackEntry> stack;
- stack.reserve(BVHParams::MAX_DEPTH*2);
- if(root->is_leaf()) {
- stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
- }
- else {
- stack.push_back(BVHStackEntry(root, nextNodeIdx));
- nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_NODE_SIZE
- : BVH_NODE_SIZE;
- }
-
- while(stack.size()) {
- BVHStackEntry e = stack.back();
- stack.pop_back();
-
- if(e.node->is_leaf()) {
- /* leaf node */
- const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
- pack_leaf(e, leaf);
- }
- else {
- /* inner node */
- int idx[2];
- for(int i = 0; i < 2; ++i) {
- if(e.node->get_child(i)->is_leaf()) {
- idx[i] = nextLeafNodeIdx++;
- }
- else {
- idx[i] = nextNodeIdx;
- nextNodeIdx += e.node->get_child(i)->has_unaligned()
- ? BVH_UNALIGNED_NODE_SIZE
- : BVH_NODE_SIZE;
- }
- }
-
- stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0]));
- stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1]));
-
- pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
- }
- }
- assert(node_size == nextNodeIdx);
- /* root index to start traversal at, to handle case of single leaf node */
- pack.root_index = (root->is_leaf())? -1: 0;
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if (params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes = root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_NODE_SIZE;
+ }
+ /* Resize arrays */
+ pack.nodes.clear();
+ pack.leaf_nodes.clear();
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
+ if (params.top_level) {
+ pack_instances(node_size, num_leaf_nodes * BVH_NODE_LEAF_SIZE);
+ }
+ else {
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes * BVH_NODE_LEAF_SIZE);
+ }
+
+ int nextNodeIdx = 0, nextLeafNodeIdx = 0;
+
+ vector<BVHStackEntry> stack;
+ stack.reserve(BVHParams::MAX_DEPTH * 2);
+ if (root->is_leaf()) {
+ stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_NODE_SIZE : BVH_NODE_SIZE;
+ }
+
+ while (stack.size()) {
+ BVHStackEntry e = stack.back();
+ stack.pop_back();
+
+ if (e.node->is_leaf()) {
+ /* leaf node */
+ const LeafNode *leaf = reinterpret_cast<const LeafNode *>(e.node);
+ pack_leaf(e, leaf);
+ }
+ else {
+ /* inner node */
+ int idx[2];
+ for (int i = 0; i < 2; ++i) {
+ if (e.node->get_child(i)->is_leaf()) {
+ idx[i] = nextLeafNodeIdx++;
+ }
+ else {
+ idx[i] = nextNodeIdx;
+ nextNodeIdx += e.node->get_child(i)->has_unaligned() ? BVH_UNALIGNED_NODE_SIZE :
+ BVH_NODE_SIZE;
+ }
+ }
+
+ stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0]));
+ stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1]));
+
+ pack_inner(e, stack[stack.size() - 2], stack[stack.size() - 1]);
+ }
+ }
+ assert(node_size == nextNodeIdx);
+ /* root index to start traversal at, to handle case of single leaf node */
+ pack.root_index = (root->is_leaf()) ? -1 : 0;
}
void BVH2::refit_nodes()
{
- assert(!params.top_level);
+ assert(!params.top_level);
- BoundBox bbox = BoundBox::empty;
- uint visibility = 0;
- refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility);
+ BoundBox bbox = BoundBox::empty;
+ uint visibility = 0;
+ refit_node(0, (pack.root_index == -1) ? true : false, bbox, visibility);
}
-void BVH2::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
+void BVH2::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
{
- if(leaf) {
- /* refit leaf node */
- assert(idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
- const int4 *data = &pack.leaf_nodes[idx];
- const int c0 = data[0].x;
- const int c1 = data[0].y;
-
- BVH::refit_primitives(c0, c1, bbox, visibility);
-
- /* TODO(sergey): De-duplicate with pack_leaf(). */
- float4 leaf_data[BVH_NODE_LEAF_SIZE];
- leaf_data[0].x = __int_as_float(c0);
- leaf_data[0].y = __int_as_float(c1);
- leaf_data[0].z = __uint_as_float(visibility);
- leaf_data[0].w = __uint_as_float(data[0].w);
- memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
- }
- else {
- assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
-
- const int4 *data = &pack.nodes[idx];
- const bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
- const int c0 = data[0].z;
- const int c1 = data[0].w;
- /* refit inner node, set bbox from children */
- BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty;
- uint visibility0 = 0, visibility1 = 0;
-
- refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
- refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
-
- if(is_unaligned) {
- Transform aligned_space = transform_identity();
- pack_unaligned_node(idx,
- aligned_space, aligned_space,
- bbox0, bbox1,
- c0, c1,
- visibility0,
- visibility1);
- }
- else {
- pack_aligned_node(idx,
- bbox0, bbox1,
- c0, c1,
- visibility0,
- visibility1);
- }
-
- bbox.grow(bbox0);
- bbox.grow(bbox1);
- visibility = visibility0|visibility1;
- }
+ if (leaf) {
+ /* refit leaf node */
+ assert(idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
+ const int4 *data = &pack.leaf_nodes[idx];
+ const int c0 = data[0].x;
+ const int c1 = data[0].y;
+
+ BVH::refit_primitives(c0, c1, bbox, visibility);
+
+ /* TODO(sergey): De-duplicate with pack_leaf(). */
+ float4 leaf_data[BVH_NODE_LEAF_SIZE];
+ leaf_data[0].x = __int_as_float(c0);
+ leaf_data[0].y = __int_as_float(c1);
+ leaf_data[0].z = __uint_as_float(visibility);
+ leaf_data[0].w = __uint_as_float(data[0].w);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4) * BVH_NODE_LEAF_SIZE);
+ }
+ else {
+ assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
+
+ const int4 *data = &pack.nodes[idx];
+ const bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
+ const int c0 = data[0].z;
+ const int c1 = data[0].w;
+ /* refit inner node, set bbox from children */
+ BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty;
+ uint visibility0 = 0, visibility1 = 0;
+
+ refit_node((c0 < 0) ? -c0 - 1 : c0, (c0 < 0), bbox0, visibility0);
+ refit_node((c1 < 0) ? -c1 - 1 : c1, (c1 < 0), bbox1, visibility1);
+
+ if (is_unaligned) {
+ Transform aligned_space = transform_identity();
+ pack_unaligned_node(
+ idx, aligned_space, aligned_space, bbox0, bbox1, c0, c1, visibility0, visibility1);
+ }
+ else {
+ pack_aligned_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
+ }
+
+ bbox.grow(bbox0);
+ bbox.grow(bbox1);
+ visibility = visibility0 | visibility1;
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h
index 6afa6c21796..c6a4e6fa73a 100644
--- a/intern/cycles/bvh/bvh2.h
+++ b/intern/cycles/bvh/bvh2.h
@@ -34,8 +34,8 @@ class LeafNode;
class Object;
class Progress;
-#define BVH_NODE_SIZE 4
-#define BVH_NODE_LEAF_SIZE 1
+#define BVH_NODE_SIZE 4
+#define BVH_NODE_LEAF_SIZE 1
#define BVH_UNALIGNED_NODE_SIZE 7
/* BVH2
@@ -43,48 +43,49 @@ class Progress;
* Typical BVH with each node having two children.
*/
class BVH2 : public BVH {
-protected:
- /* constructor */
- friend class BVH;
- BVH2(const BVHParams& params, const vector<Object*>& objects);
+ protected:
+ /* constructor */
+ friend class BVH;
+ BVH2(const BVHParams &params, const vector<Object *> &objects);
- /* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+ /* Building process. */
+ virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
- /* pack */
- void pack_nodes(const BVHNode *root) override;
+ /* pack */
+ void pack_nodes(const BVHNode *root) override;
- void pack_leaf(const BVHStackEntry& e,
- const LeafNode *leaf);
- void pack_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1);
+ void pack_leaf(const BVHStackEntry &e, const LeafNode *leaf);
+ void pack_inner(const BVHStackEntry &e, const BVHStackEntry &e0, const BVHStackEntry &e1);
- void pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1);
- void pack_aligned_node(int idx,
- const BoundBox& b0,
- const BoundBox& b1,
- int c0, int c1,
- uint visibility0, uint visibility1);
+ void pack_aligned_inner(const BVHStackEntry &e,
+ const BVHStackEntry &e0,
+ const BVHStackEntry &e1);
+ void pack_aligned_node(int idx,
+ const BoundBox &b0,
+ const BoundBox &b1,
+ int c0,
+ int c1,
+ uint visibility0,
+ uint visibility1);
- void pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry& e0,
- const BVHStackEntry& e1);
- void pack_unaligned_node(int idx,
- const Transform& aligned_space0,
- const Transform& aligned_space1,
- const BoundBox& b0,
- const BoundBox& b1,
- int c0, int c1,
- uint visibility0, uint visibility1);
+ void pack_unaligned_inner(const BVHStackEntry &e,
+ const BVHStackEntry &e0,
+ const BVHStackEntry &e1);
+ void pack_unaligned_node(int idx,
+ const Transform &aligned_space0,
+ const Transform &aligned_space1,
+ const BoundBox &b0,
+ const BoundBox &b1,
+ int c0,
+ int c1,
+ uint visibility0,
+ uint visibility1);
- /* refit */
- void refit_nodes() override;
- void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
+ /* refit */
+ void refit_nodes() override;
+ void refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility);
};
CCL_NAMESPACE_END
-#endif /* __BVH2_H__ */
+#endif /* __BVH2_H__ */
diff --git a/intern/cycles/bvh/bvh4.cpp b/intern/cycles/bvh/bvh4.cpp
index a7c4cea85ce..850bdf5b8b4 100644
--- a/intern/cycles/bvh/bvh4.cpp
+++ b/intern/cycles/bvh/bvh4.cpp
@@ -31,141 +31,131 @@ CCL_NAMESPACE_BEGIN
* life easier all over the place.
*/
-BVH4::BVH4(const BVHParams& params_, const vector<Object*>& objects_)
-: BVH(params_, objects_)
+BVH4::BVH4(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
{
- params.bvh_layout = BVH_LAYOUT_BVH4;
+ params.bvh_layout = BVH_LAYOUT_BVH4;
}
namespace {
BVHNode *bvh_node_merge_children_recursively(const BVHNode *node)
{
- if(node->is_leaf()) {
- return new LeafNode(*reinterpret_cast<const LeafNode *>(node));
- }
- /* Collect nodes of one layer deeper, allowing us to have more childrem in
- * an inner layer. */
- assert(node->num_children() <= 2);
- const BVHNode *children[4];
- const BVHNode *child0 = node->get_child(0);
- const BVHNode *child1 = node->get_child(1);
- int num_children = 0;
- if(child0->is_leaf()) {
- children[num_children++] = child0;
- }
- else {
- children[num_children++] = child0->get_child(0);
- children[num_children++] = child0->get_child(1);
- }
- if(child1->is_leaf()) {
- children[num_children++] = child1;
- }
- else {
- children[num_children++] = child1->get_child(0);
- children[num_children++] = child1->get_child(1);
- }
- /* Merge children in subtrees. */
- BVHNode *children4[4];
- for(int i = 0; i < num_children; ++i) {
- children4[i] = bvh_node_merge_children_recursively(children[i]);
- }
- /* Allocate new node. */
- BVHNode *node4 = new InnerNode(node->bounds, children4, num_children);
- /* TODO(sergey): Consider doing this from the InnerNode() constructor.
- * But in order to do this nicely need to think of how to pass all the
- * parameters there. */
- if(node->is_unaligned) {
- node4->is_unaligned = true;
- node4->aligned_space = new Transform();
- *node4->aligned_space = *node->aligned_space;
- }
- return node4;
+ if (node->is_leaf()) {
+ return new LeafNode(*reinterpret_cast<const LeafNode *>(node));
+ }
+ /* Collect nodes of one layer deeper, allowing us to have more childrem in
+ * an inner layer. */
+ assert(node->num_children() <= 2);
+ const BVHNode *children[4];
+ const BVHNode *child0 = node->get_child(0);
+ const BVHNode *child1 = node->get_child(1);
+ int num_children = 0;
+ if (child0->is_leaf()) {
+ children[num_children++] = child0;
+ }
+ else {
+ children[num_children++] = child0->get_child(0);
+ children[num_children++] = child0->get_child(1);
+ }
+ if (child1->is_leaf()) {
+ children[num_children++] = child1;
+ }
+ else {
+ children[num_children++] = child1->get_child(0);
+ children[num_children++] = child1->get_child(1);
+ }
+ /* Merge children in subtrees. */
+ BVHNode *children4[4];
+ for (int i = 0; i < num_children; ++i) {
+ children4[i] = bvh_node_merge_children_recursively(children[i]);
+ }
+ /* Allocate new node. */
+ BVHNode *node4 = new InnerNode(node->bounds, children4, num_children);
+ /* TODO(sergey): Consider doing this from the InnerNode() constructor.
+ * But in order to do this nicely need to think of how to pass all the
+ * parameters there. */
+ if (node->is_unaligned) {
+ node4->is_unaligned = true;
+ node4->aligned_space = new Transform();
+ *node4->aligned_space = *node->aligned_space;
+ }
+ return node4;
}
} // namespace
BVHNode *BVH4::widen_children_nodes(const BVHNode *root)
{
- if(root == NULL) {
- return NULL;
- }
- if(root->is_leaf()) {
- return const_cast<BVHNode *>(root);
- }
- BVHNode *root4 = bvh_node_merge_children_recursively(root);
- /* TODO(sergey): Pack children nodes to parents which has less that 4
- * children. */
- return root4;
+ if (root == NULL) {
+ return NULL;
+ }
+ if (root->is_leaf()) {
+ return const_cast<BVHNode *>(root);
+ }
+ BVHNode *root4 = bvh_node_merge_children_recursively(root);
+ /* TODO(sergey): Pack children nodes to parents which has less that 4
+ * children. */
+ return root4;
}
-void BVH4::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+void BVH4::pack_leaf(const BVHStackEntry &e, const LeafNode *leaf)
{
- float4 data[BVH_QNODE_LEAF_SIZE];
- memset(data, 0, sizeof(data));
- if(leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
- /* object */
- data[0].x = __int_as_float(~(leaf->lo));
- data[0].y = __int_as_float(0);
- }
- else {
- /* triangle */
- data[0].x = __int_as_float(leaf->lo);
- data[0].y = __int_as_float(leaf->hi);
- }
- data[0].z = __uint_as_float(leaf->visibility);
- if(leaf->num_triangles() != 0) {
- data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
- }
-
- memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+ float4 data[BVH_QNODE_LEAF_SIZE];
+ memset(data, 0, sizeof(data));
+ if (leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
+ /* object */
+ data[0].x = __int_as_float(~(leaf->lo));
+ data[0].y = __int_as_float(0);
+ }
+ else {
+ /* triangle */
+ data[0].x = __int_as_float(leaf->lo);
+ data[0].y = __int_as_float(leaf->hi);
+ }
+ data[0].z = __uint_as_float(leaf->visibility);
+ if (leaf->num_triangles() != 0) {
+ data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
+ }
+
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4) * BVH_QNODE_LEAF_SIZE);
}
-void BVH4::pack_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH4::pack_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- bool has_unaligned = false;
- /* Check whether we have to create unaligned node or all nodes are aligned
- * and we can cut some corner here.
- */
- if(params.use_unaligned_nodes) {
- for(int i = 0; i < num; i++) {
- if(en[i].node->is_unaligned) {
- has_unaligned = true;
- break;
- }
- }
- }
- if(has_unaligned) {
- /* There's no unaligned children, pack into AABB node. */
- pack_unaligned_inner(e, en, num);
- }
- else {
- /* Create unaligned node with orientation transform for each of the
- * children.
- */
- pack_aligned_inner(e, en, num);
- }
+ bool has_unaligned = false;
+ /* Check whether we have to create unaligned node or all nodes are aligned
+ * and we can cut some corner here.
+ */
+ if (params.use_unaligned_nodes) {
+ for (int i = 0; i < num; i++) {
+ if (en[i].node->is_unaligned) {
+ has_unaligned = true;
+ break;
+ }
+ }
+ }
+ if (has_unaligned) {
+ /* There's no unaligned children, pack into AABB node. */
+ pack_unaligned_inner(e, en, num);
+ }
+ else {
+ /* Create unaligned node with orientation transform for each of the
+ * children.
+ */
+ pack_aligned_inner(e, en, num);
+ }
}
-void BVH4::pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH4::pack_aligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- BoundBox bounds[4];
- int child[4];
- for(int i = 0; i < num; ++i) {
- bounds[i] = en[i].node->bounds;
- child[i] = en[i].encodeIdx();
- }
- pack_aligned_node(e.idx,
- bounds,
- child,
- e.node->visibility,
- e.node->time_from,
- e.node->time_to,
- num);
+ BoundBox bounds[4];
+ int child[4];
+ for (int i = 0; i < num; ++i) {
+ bounds[i] = en[i].node->bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_aligned_node(
+ e.idx, bounds, child, e.node->visibility, e.node->time_from, e.node->time_to, num);
}
void BVH4::pack_aligned_node(int idx,
@@ -176,66 +166,64 @@ void BVH4::pack_aligned_node(int idx,
const float time_to,
const int num)
{
- float4 data[BVH_QNODE_SIZE];
- memset(data, 0, sizeof(data));
+ float4 data[BVH_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
- data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
- data[0].y = time_from;
- data[0].z = time_to;
+ data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
+ data[0].y = time_from;
+ data[0].z = time_to;
- for(int i = 0; i < num; i++) {
- float3 bb_min = bounds[i].min;
- float3 bb_max = bounds[i].max;
+ for (int i = 0; i < num; i++) {
+ float3 bb_min = bounds[i].min;
+ float3 bb_max = bounds[i].max;
- data[1][i] = bb_min.x;
- data[2][i] = bb_max.x;
- data[3][i] = bb_min.y;
- data[4][i] = bb_max.y;
- data[5][i] = bb_min.z;
- data[6][i] = bb_max.z;
+ data[1][i] = bb_min.x;
+ data[2][i] = bb_max.x;
+ data[3][i] = bb_min.y;
+ data[4][i] = bb_max.y;
+ data[5][i] = bb_min.z;
+ data[6][i] = bb_max.z;
- data[7][i] = __int_as_float(child[i]);
- }
+ data[7][i] = __int_as_float(child[i]);
+ }
- for(int i = num; i < 4; i++) {
- /* We store BB which would never be recorded as intersection
- * so kernel might safely assume there are always 4 child nodes.
- */
- data[1][i] = FLT_MAX;
- data[2][i] = -FLT_MAX;
+ for (int i = num; i < 4; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
+ data[1][i] = FLT_MAX;
+ data[2][i] = -FLT_MAX;
- data[3][i] = FLT_MAX;
- data[4][i] = -FLT_MAX;
+ data[3][i] = FLT_MAX;
+ data[4][i] = -FLT_MAX;
- data[5][i] = FLT_MAX;
- data[6][i] = -FLT_MAX;
+ data[5][i] = FLT_MAX;
+ data[6][i] = -FLT_MAX;
- data[7][i] = __int_as_float(0);
- }
+ data[7][i] = __int_as_float(0);
+ }
- memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_QNODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(float4) * BVH_QNODE_SIZE);
}
-void BVH4::pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH4::pack_unaligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- Transform aligned_space[4];
- BoundBox bounds[4];
- int child[4];
- for(int i = 0; i < num; ++i) {
- aligned_space[i] = en[i].node->get_aligned_space();
- bounds[i] = en[i].node->bounds;
- child[i] = en[i].encodeIdx();
- }
- pack_unaligned_node(e.idx,
- aligned_space,
- bounds,
- child,
- e.node->visibility,
- e.node->time_from,
- e.node->time_to,
- num);
+ Transform aligned_space[4];
+ BoundBox bounds[4];
+ int child[4];
+ for (int i = 0; i < num; ++i) {
+ aligned_space[i] = en[i].node->get_aligned_space();
+ bounds[i] = en[i].node->bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_unaligned_node(e.idx,
+ aligned_space,
+ bounds,
+ child,
+ e.node->visibility,
+ e.node->time_from,
+ e.node->time_to,
+ num);
}
void BVH4::pack_unaligned_node(int idx,
@@ -247,235 +235,211 @@ void BVH4::pack_unaligned_node(int idx,
const float time_to,
const int num)
{
- float4 data[BVH_UNALIGNED_QNODE_SIZE];
- memset(data, 0, sizeof(data));
+ float4 data[BVH_UNALIGNED_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
- data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED);
- data[0].y = time_from;
- data[0].z = time_to;
+ data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED);
+ data[0].y = time_from;
+ data[0].z = time_to;
- for(int i = 0; i < num; i++) {
- Transform space = BVHUnaligned::compute_node_transform(
- bounds[i],
- aligned_space[i]);
+ for (int i = 0; i < num; i++) {
+ Transform space = BVHUnaligned::compute_node_transform(bounds[i], aligned_space[i]);
- data[1][i] = space.x.x;
- data[2][i] = space.x.y;
- data[3][i] = space.x.z;
+ data[1][i] = space.x.x;
+ data[2][i] = space.x.y;
+ data[3][i] = space.x.z;
- data[4][i] = space.y.x;
- data[5][i] = space.y.y;
- data[6][i] = space.y.z;
+ data[4][i] = space.y.x;
+ data[5][i] = space.y.y;
+ data[6][i] = space.y.z;
- data[7][i] = space.z.x;
- data[8][i] = space.z.y;
- data[9][i] = space.z.z;
+ data[7][i] = space.z.x;
+ data[8][i] = space.z.y;
+ data[9][i] = space.z.z;
- data[10][i] = space.x.w;
- data[11][i] = space.y.w;
- data[12][i] = space.z.w;
+ data[10][i] = space.x.w;
+ data[11][i] = space.y.w;
+ data[12][i] = space.z.w;
- data[13][i] = __int_as_float(child[i]);
- }
+ data[13][i] = __int_as_float(child[i]);
+ }
- for(int i = num; i < 4; i++) {
- /* We store BB which would never be recorded as intersection
- * so kernel might safely assume there are always 4 child nodes.
- */
+ for (int i = num; i < 4; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
- data[1][i] = NAN;
- data[2][i] = NAN;
- data[3][i] = NAN;
+ data[1][i] = NAN;
+ data[2][i] = NAN;
+ data[3][i] = NAN;
- data[4][i] = NAN;
- data[5][i] = NAN;
- data[6][i] = NAN;
+ data[4][i] = NAN;
+ data[5][i] = NAN;
+ data[6][i] = NAN;
- data[7][i] = NAN;
- data[8][i] = NAN;
- data[9][i] = NAN;
+ data[7][i] = NAN;
+ data[8][i] = NAN;
+ data[9][i] = NAN;
- data[10][i] = NAN;
- data[11][i] = NAN;
- data[12][i] = NAN;
+ data[10][i] = NAN;
+ data[11][i] = NAN;
+ data[12][i] = NAN;
- data[13][i] = __int_as_float(0);
- }
+ data[13][i] = __int_as_float(0);
+ }
- memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(float4) * BVH_UNALIGNED_QNODE_SIZE);
}
/* Quad SIMD Nodes */
void BVH4::pack_nodes(const BVHNode *root)
{
- /* Calculate size of the arrays required. */
- const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
- const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- assert(num_leaf_nodes <= num_nodes);
- const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
- size_t node_size;
- if(params.use_unaligned_nodes) {
- const size_t num_unaligned_nodes =
- root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
- node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) +
- (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE;
- }
- else {
- node_size = num_inner_nodes * BVH_QNODE_SIZE;
- }
- /* Resize arrays. */
- pack.nodes.clear();
- pack.leaf_nodes.clear();
- /* For top level BVH, first merge existing BVH's so we know the offsets. */
- if(params.top_level) {
- pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
- }
- else {
- pack.nodes.resize(node_size);
- pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
- }
-
- int nextNodeIdx = 0, nextLeafNodeIdx = 0;
-
- vector<BVHStackEntry> stack;
- stack.reserve(BVHParams::MAX_DEPTH*2);
- if(root->is_leaf()) {
- stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
- }
- else {
- stack.push_back(BVHStackEntry(root, nextNodeIdx));
- nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_QNODE_SIZE
- : BVH_QNODE_SIZE;
- }
-
- while(stack.size()) {
- BVHStackEntry e = stack.back();
- stack.pop_back();
-
- if(e.node->is_leaf()) {
- /* leaf node */
- const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
- pack_leaf(e, leaf);
- }
- else {
- /* Inner node. */
- /* Collect nodes. */
- const BVHNode *children[4];
- const int num_children = e.node->num_children();
- /* Push entries on the stack. */
- for(int i = 0; i < num_children; ++i) {
- int idx;
- children[i] = e.node->get_child(i);
- assert(children[i] != NULL);
- if(children[i]->is_leaf()) {
- idx = nextLeafNodeIdx++;
- }
- else {
- idx = nextNodeIdx;
- nextNodeIdx += children[i]->has_unaligned()
- ? BVH_UNALIGNED_QNODE_SIZE
- : BVH_QNODE_SIZE;
- }
- stack.push_back(BVHStackEntry(children[i], idx));
- }
- /* Set node. */
- pack_inner(e, &stack[stack.size() - num_children], num_children);
- }
- }
-
- assert(node_size == nextNodeIdx);
- /* Root index to start traversal at, to handle case of single leaf node. */
- pack.root_index = (root->is_leaf())? -1: 0;
+ /* Calculate size of the arrays required. */
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if (params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes = root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_QNODE_SIZE;
+ }
+ /* Resize arrays. */
+ pack.nodes.clear();
+ pack.leaf_nodes.clear();
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
+ if (params.top_level) {
+ pack_instances(node_size, num_leaf_nodes * BVH_QNODE_LEAF_SIZE);
+ }
+ else {
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes * BVH_QNODE_LEAF_SIZE);
+ }
+
+ int nextNodeIdx = 0, nextLeafNodeIdx = 0;
+
+ vector<BVHStackEntry> stack;
+ stack.reserve(BVHParams::MAX_DEPTH * 2);
+ if (root->is_leaf()) {
+ stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_QNODE_SIZE : BVH_QNODE_SIZE;
+ }
+
+ while (stack.size()) {
+ BVHStackEntry e = stack.back();
+ stack.pop_back();
+
+ if (e.node->is_leaf()) {
+ /* leaf node */
+ const LeafNode *leaf = reinterpret_cast<const LeafNode *>(e.node);
+ pack_leaf(e, leaf);
+ }
+ else {
+ /* Inner node. */
+ /* Collect nodes. */
+ const BVHNode *children[4];
+ const int num_children = e.node->num_children();
+ /* Push entries on the stack. */
+ for (int i = 0; i < num_children; ++i) {
+ int idx;
+ children[i] = e.node->get_child(i);
+ assert(children[i] != NULL);
+ if (children[i]->is_leaf()) {
+ idx = nextLeafNodeIdx++;
+ }
+ else {
+ idx = nextNodeIdx;
+ nextNodeIdx += children[i]->has_unaligned() ? BVH_UNALIGNED_QNODE_SIZE : BVH_QNODE_SIZE;
+ }
+ stack.push_back(BVHStackEntry(children[i], idx));
+ }
+ /* Set node. */
+ pack_inner(e, &stack[stack.size() - num_children], num_children);
+ }
+ }
+
+ assert(node_size == nextNodeIdx);
+ /* Root index to start traversal at, to handle case of single leaf node. */
+ pack.root_index = (root->is_leaf()) ? -1 : 0;
}
void BVH4::refit_nodes()
{
- assert(!params.top_level);
+ assert(!params.top_level);
- BoundBox bbox = BoundBox::empty;
- uint visibility = 0;
- refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility);
+ BoundBox bbox = BoundBox::empty;
+ uint visibility = 0;
+ refit_node(0, (pack.root_index == -1) ? true : false, bbox, visibility);
}
-void BVH4::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
+void BVH4::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
{
- if(leaf) {
- /* Refit leaf node. */
- int4 *data = &pack.leaf_nodes[idx];
- int4 c = data[0];
-
- BVH::refit_primitives(c.x, c.y, bbox, visibility);
-
- /* TODO(sergey): This is actually a copy of pack_leaf(),
- * but this chunk of code only knows actual data and has
- * no idea about BVHNode.
- *
- * Would be nice to de-duplicate code, but trying to make
- * making code more general ends up in much nastier code
- * in my opinion so far.
- *
- * Same applies to the inner nodes case below.
- */
- float4 leaf_data[BVH_QNODE_LEAF_SIZE];
- leaf_data[0].x = __int_as_float(c.x);
- leaf_data[0].y = __int_as_float(c.y);
- leaf_data[0].z = __uint_as_float(visibility);
- leaf_data[0].w = __uint_as_float(c.w);
- memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
- }
- else {
- int4 *data = &pack.nodes[idx];
- bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
- int4 c;
- if(is_unaligned) {
- c = data[13];
- }
- else {
- c = data[7];
- }
- /* Refit inner node, set bbox from children. */
- BoundBox child_bbox[4] = {BoundBox::empty,
- BoundBox::empty,
- BoundBox::empty,
- BoundBox::empty};
- uint child_visibility[4] = {0};
- int num_nodes = 0;
-
- for(int i = 0; i < 4; ++i) {
- if(c[i] != 0) {
- refit_node((c[i] < 0)? -c[i]-1: c[i], (c[i] < 0),
- child_bbox[i], child_visibility[i]);
- ++num_nodes;
- bbox.grow(child_bbox[i]);
- visibility |= child_visibility[i];
- }
- }
-
- if(is_unaligned) {
- Transform aligned_space[4] = {transform_identity(),
- transform_identity(),
- transform_identity(),
- transform_identity()};
- pack_unaligned_node(idx,
- aligned_space,
- child_bbox,
- &c[0],
- visibility,
- 0.0f,
- 1.0f,
- num_nodes);
- }
- else {
- pack_aligned_node(idx,
- child_bbox,
- &c[0],
- visibility,
- 0.0f,
- 1.0f,
- num_nodes);
- }
- }
+ if (leaf) {
+ /* Refit leaf node. */
+ int4 *data = &pack.leaf_nodes[idx];
+ int4 c = data[0];
+
+ BVH::refit_primitives(c.x, c.y, bbox, visibility);
+
+ /* TODO(sergey): This is actually a copy of pack_leaf(),
+ * but this chunk of code only knows actual data and has
+ * no idea about BVHNode.
+ *
+ * Would be nice to de-duplicate code, but trying to make
+ * making code more general ends up in much nastier code
+ * in my opinion so far.
+ *
+ * Same applies to the inner nodes case below.
+ */
+ float4 leaf_data[BVH_QNODE_LEAF_SIZE];
+ leaf_data[0].x = __int_as_float(c.x);
+ leaf_data[0].y = __int_as_float(c.y);
+ leaf_data[0].z = __uint_as_float(visibility);
+ leaf_data[0].w = __uint_as_float(c.w);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4) * BVH_QNODE_LEAF_SIZE);
+ }
+ else {
+ int4 *data = &pack.nodes[idx];
+ bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
+ int4 c;
+ if (is_unaligned) {
+ c = data[13];
+ }
+ else {
+ c = data[7];
+ }
+ /* Refit inner node, set bbox from children. */
+ BoundBox child_bbox[4] = {BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
+ uint child_visibility[4] = {0};
+ int num_nodes = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ if (c[i] != 0) {
+ refit_node((c[i] < 0) ? -c[i] - 1 : c[i], (c[i] < 0), child_bbox[i], child_visibility[i]);
+ ++num_nodes;
+ bbox.grow(child_bbox[i]);
+ visibility |= child_visibility[i];
+ }
+ }
+
+ if (is_unaligned) {
+ Transform aligned_space[4] = {
+ transform_identity(), transform_identity(), transform_identity(), transform_identity()};
+ pack_unaligned_node(
+ idx, aligned_space, child_bbox, &c[0], visibility, 0.0f, 1.0f, num_nodes);
+ }
+ else {
+ pack_aligned_node(idx, child_bbox, &c[0], visibility, 0.0f, 1.0f, num_nodes);
+ }
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh4.h b/intern/cycles/bvh/bvh4.h
index caa0e2c8182..38b0961d3df 100644
--- a/intern/cycles/bvh/bvh4.h
+++ b/intern/cycles/bvh/bvh4.h
@@ -34,8 +34,8 @@ class LeafNode;
class Object;
class Progress;
-#define BVH_QNODE_SIZE 8
-#define BVH_QNODE_LEAF_SIZE 1
+#define BVH_QNODE_SIZE 8
+#define BVH_QNODE_LEAF_SIZE 1
#define BVH_UNALIGNED_QNODE_SIZE 14
/* BVH4
@@ -43,48 +43,44 @@ class Progress;
* Quad BVH, with each node having four children, to use with SIMD instructions.
*/
class BVH4 : public BVH {
-protected:
- /* constructor */
- friend class BVH;
- BVH4(const BVHParams& params, const vector<Object*>& objects);
+ protected:
+ /* constructor */
+ friend class BVH;
+ BVH4(const BVHParams &params, const vector<Object *> &objects);
- /* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+ /* Building process. */
+ virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
- /* pack */
- void pack_nodes(const BVHNode *root) override;
+ /* pack */
+ void pack_nodes(const BVHNode *root) override;
- void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
- void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
+ void pack_leaf(const BVHStackEntry &e, const LeafNode *leaf);
+ void pack_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
- void pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num);
- void pack_aligned_node(int idx,
- const BoundBox *bounds,
- const int *child,
- const uint visibility,
- const float time_from,
- const float time_to,
- const int num);
+ void pack_aligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
+ void pack_aligned_node(int idx,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const float time_from,
+ const float time_to,
+ const int num);
- void pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num);
- void pack_unaligned_node(int idx,
- const Transform *aligned_space,
- const BoundBox *bounds,
- const int *child,
- const uint visibility,
- const float time_from,
- const float time_to,
- const int num);
+ void pack_unaligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
+ void pack_unaligned_node(int idx,
+ const Transform *aligned_space,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const float time_from,
+ const float time_to,
+ const int num);
- /* refit */
- void refit_nodes() override;
- void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
+ /* refit */
+ void refit_nodes() override;
+ void refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility);
};
CCL_NAMESPACE_END
-#endif /* __BVH4_H__ */
+#endif /* __BVH4_H__ */
diff --git a/intern/cycles/bvh/bvh8.cpp b/intern/cycles/bvh/bvh8.cpp
index af930b2f2df..e812d806b94 100644
--- a/intern/cycles/bvh/bvh8.cpp
+++ b/intern/cycles/bvh/bvh8.cpp
@@ -36,8 +36,7 @@
CCL_NAMESPACE_BEGIN
-BVH8::BVH8(const BVHParams& params_, const vector<Object*>& objects_)
-: BVH(params_, objects_)
+BVH8::BVH8(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
{
}
@@ -45,159 +44,148 @@ namespace {
BVHNode *bvh_node_merge_children_recursively(const BVHNode *node)
{
- if(node->is_leaf()) {
- return new LeafNode(*reinterpret_cast<const LeafNode *>(node));
- }
- /* Collect nodes of two layer deeper, allowing us to have more childrem in
- * an inner layer. */
- assert(node->num_children() <= 2);
- const BVHNode *children[8];
- const BVHNode *child0 = node->get_child(0);
- const BVHNode *child1 = node->get_child(1);
- int num_children = 0;
- if(child0->is_leaf()) {
- children[num_children++] = child0;
- }
- else {
- const BVHNode *child00 = child0->get_child(0),
- *child01 = child0->get_child(1);
- if(child00->is_leaf()) {
- children[num_children++] = child00;
- }
- else {
- children[num_children++] = child00->get_child(0);
- children[num_children++] = child00->get_child(1);
- }
- if(child01->is_leaf()) {
- children[num_children++] = child01;
- }
- else {
- children[num_children++] = child01->get_child(0);
- children[num_children++] = child01->get_child(1);
- }
- }
- if(child1->is_leaf()) {
- children[num_children++] = child1;
- }
- else {
- const BVHNode *child10 = child1->get_child(0),
- *child11 = child1->get_child(1);
- if(child10->is_leaf()) {
- children[num_children++] = child10;
- }
- else {
- children[num_children++] = child10->get_child(0);
- children[num_children++] = child10->get_child(1);
- }
- if(child11->is_leaf()) {
- children[num_children++] = child11;
- }
- else {
- children[num_children++] = child11->get_child(0);
- children[num_children++] = child11->get_child(1);
- }
- }
- /* Merge children in subtrees. */
- BVHNode *children4[8];
- for(int i = 0; i < num_children; ++i) {
- children4[i] = bvh_node_merge_children_recursively(children[i]);
- }
- /* Allocate new node. */
- BVHNode *node8 = new InnerNode(node->bounds, children4, num_children);
- /* TODO(sergey): Consider doing this from the InnerNode() constructor.
- * But in order to do this nicely need to think of how to pass all the
- * parameters there. */
- if(node->is_unaligned) {
- node8->is_unaligned = true;
- node8->aligned_space = new Transform();
- *node8->aligned_space = *node->aligned_space;
- }
- return node8;
+ if (node->is_leaf()) {
+ return new LeafNode(*reinterpret_cast<const LeafNode *>(node));
+ }
+ /* Collect nodes of two layer deeper, allowing us to have more childrem in
+ * an inner layer. */
+ assert(node->num_children() <= 2);
+ const BVHNode *children[8];
+ const BVHNode *child0 = node->get_child(0);
+ const BVHNode *child1 = node->get_child(1);
+ int num_children = 0;
+ if (child0->is_leaf()) {
+ children[num_children++] = child0;
+ }
+ else {
+ const BVHNode *child00 = child0->get_child(0), *child01 = child0->get_child(1);
+ if (child00->is_leaf()) {
+ children[num_children++] = child00;
+ }
+ else {
+ children[num_children++] = child00->get_child(0);
+ children[num_children++] = child00->get_child(1);
+ }
+ if (child01->is_leaf()) {
+ children[num_children++] = child01;
+ }
+ else {
+ children[num_children++] = child01->get_child(0);
+ children[num_children++] = child01->get_child(1);
+ }
+ }
+ if (child1->is_leaf()) {
+ children[num_children++] = child1;
+ }
+ else {
+ const BVHNode *child10 = child1->get_child(0), *child11 = child1->get_child(1);
+ if (child10->is_leaf()) {
+ children[num_children++] = child10;
+ }
+ else {
+ children[num_children++] = child10->get_child(0);
+ children[num_children++] = child10->get_child(1);
+ }
+ if (child11->is_leaf()) {
+ children[num_children++] = child11;
+ }
+ else {
+ children[num_children++] = child11->get_child(0);
+ children[num_children++] = child11->get_child(1);
+ }
+ }
+ /* Merge children in subtrees. */
+ BVHNode *children4[8];
+ for (int i = 0; i < num_children; ++i) {
+ children4[i] = bvh_node_merge_children_recursively(children[i]);
+ }
+ /* Allocate new node. */
+ BVHNode *node8 = new InnerNode(node->bounds, children4, num_children);
+ /* TODO(sergey): Consider doing this from the InnerNode() constructor.
+ * But in order to do this nicely need to think of how to pass all the
+ * parameters there. */
+ if (node->is_unaligned) {
+ node8->is_unaligned = true;
+ node8->aligned_space = new Transform();
+ *node8->aligned_space = *node->aligned_space;
+ }
+ return node8;
}
} // namespace
BVHNode *BVH8::widen_children_nodes(const BVHNode *root)
{
- if(root == NULL) {
- return NULL;
- }
- if(root->is_leaf()) {
- return const_cast<BVHNode *>(root);
- }
- BVHNode *root8 = bvh_node_merge_children_recursively(root);
- /* TODO(sergey): Pack children nodes to parents which has less that 4
- * children. */
- return root8;
+ if (root == NULL) {
+ return NULL;
+ }
+ if (root->is_leaf()) {
+ return const_cast<BVHNode *>(root);
+ }
+ BVHNode *root8 = bvh_node_merge_children_recursively(root);
+ /* TODO(sergey): Pack children nodes to parents which has less that 4
+ * children. */
+ return root8;
}
-void BVH8::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+void BVH8::pack_leaf(const BVHStackEntry &e, const LeafNode *leaf)
{
- float4 data[BVH_ONODE_LEAF_SIZE];
- memset(data, 0, sizeof(data));
- if(leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
- /* object */
- data[0].x = __int_as_float(~(leaf->lo));
- data[0].y = __int_as_float(0);
- }
- else {
- /* triangle */
- data[0].x = __int_as_float(leaf->lo);
- data[0].y = __int_as_float(leaf->hi);
- }
- data[0].z = __uint_as_float(leaf->visibility);
- if(leaf->num_triangles() != 0) {
- data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
- }
-
- memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_ONODE_LEAF_SIZE);
+ float4 data[BVH_ONODE_LEAF_SIZE];
+ memset(data, 0, sizeof(data));
+ if (leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
+ /* object */
+ data[0].x = __int_as_float(~(leaf->lo));
+ data[0].y = __int_as_float(0);
+ }
+ else {
+ /* triangle */
+ data[0].x = __int_as_float(leaf->lo);
+ data[0].y = __int_as_float(leaf->hi);
+ }
+ data[0].z = __uint_as_float(leaf->visibility);
+ if (leaf->num_triangles() != 0) {
+ data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
+ }
+
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4) * BVH_ONODE_LEAF_SIZE);
}
-void BVH8::pack_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH8::pack_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- bool has_unaligned = false;
- /* Check whether we have to create unaligned node or all nodes are aligned
- * and we can cut some corner here.
- */
- if(params.use_unaligned_nodes) {
- for(int i = 0; i < num; i++) {
- if(en[i].node->is_unaligned) {
- has_unaligned = true;
- break;
- }
- }
- }
- if(has_unaligned) {
- /* There's no unaligned children, pack into AABB node. */
- pack_unaligned_inner(e, en, num);
- }
- else {
- /* Create unaligned node with orientation transform for each of the
- * children.
- */
- pack_aligned_inner(e, en, num);
- }
+ bool has_unaligned = false;
+ /* Check whether we have to create unaligned node or all nodes are aligned
+ * and we can cut some corner here.
+ */
+ if (params.use_unaligned_nodes) {
+ for (int i = 0; i < num; i++) {
+ if (en[i].node->is_unaligned) {
+ has_unaligned = true;
+ break;
+ }
+ }
+ }
+ if (has_unaligned) {
+ /* There's no unaligned children, pack into AABB node. */
+ pack_unaligned_inner(e, en, num);
+ }
+ else {
+ /* Create unaligned node with orientation transform for each of the
+ * children.
+ */
+ pack_aligned_inner(e, en, num);
+ }
}
-void BVH8::pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH8::pack_aligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- BoundBox bounds[8];
- int child[8];
- for(int i = 0; i < num; ++i) {
- bounds[i] = en[i].node->bounds;
- child[i] = en[i].encodeIdx();
- }
- pack_aligned_node(e.idx,
- bounds,
- child,
- e.node->visibility,
- e.node->time_from,
- e.node->time_to,
- num);
+ BoundBox bounds[8];
+ int child[8];
+ for (int i = 0; i < num; ++i) {
+ bounds[i] = en[i].node->bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_aligned_node(
+ e.idx, bounds, child, e.node->visibility, e.node->time_from, e.node->time_to, num);
}
void BVH8::pack_aligned_node(int idx,
@@ -208,66 +196,64 @@ void BVH8::pack_aligned_node(int idx,
const float time_to,
const int num)
{
- float8 data[8];
- memset(data, 0, sizeof(data));
+ float8 data[8];
+ memset(data, 0, sizeof(data));
- data[0].a = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
- data[0].b = time_from;
- data[0].c = time_to;
+ data[0].a = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
+ data[0].b = time_from;
+ data[0].c = time_to;
- for(int i = 0; i < num; i++) {
- float3 bb_min = bounds[i].min;
- float3 bb_max = bounds[i].max;
+ for (int i = 0; i < num; i++) {
+ float3 bb_min = bounds[i].min;
+ float3 bb_max = bounds[i].max;
- data[1][i] = bb_min.x;
- data[2][i] = bb_max.x;
- data[3][i] = bb_min.y;
- data[4][i] = bb_max.y;
- data[5][i] = bb_min.z;
- data[6][i] = bb_max.z;
+ data[1][i] = bb_min.x;
+ data[2][i] = bb_max.x;
+ data[3][i] = bb_min.y;
+ data[4][i] = bb_max.y;
+ data[5][i] = bb_min.z;
+ data[6][i] = bb_max.z;
- data[7][i] = __int_as_float(child[i]);
- }
+ data[7][i] = __int_as_float(child[i]);
+ }
- for(int i = num; i < 8; i++) {
- /* We store BB which would never be recorded as intersection
- * so kernel might safely assume there are always 4 child nodes.
- */
- data[1][i] = FLT_MAX;
- data[2][i] = -FLT_MAX;
+ for (int i = num; i < 8; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
+ data[1][i] = FLT_MAX;
+ data[2][i] = -FLT_MAX;
- data[3][i] = FLT_MAX;
- data[4][i] = -FLT_MAX;
+ data[3][i] = FLT_MAX;
+ data[4][i] = -FLT_MAX;
- data[5][i] = FLT_MAX;
- data[6][i] = -FLT_MAX;
+ data[5][i] = FLT_MAX;
+ data[6][i] = -FLT_MAX;
- data[7][i] = __int_as_float(0);
- }
+ data[7][i] = __int_as_float(0);
+ }
- memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_ONODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(float4) * BVH_ONODE_SIZE);
}
-void BVH8::pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num)
+void BVH8::pack_unaligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num)
{
- Transform aligned_space[8];
- BoundBox bounds[8];
- int child[8];
- for(int i = 0; i < num; ++i) {
- aligned_space[i] = en[i].node->get_aligned_space();
- bounds[i] = en[i].node->bounds;
- child[i] = en[i].encodeIdx();
- }
- pack_unaligned_node(e.idx,
- aligned_space,
- bounds,
- child,
- e.node->visibility,
- e.node->time_from,
- e.node->time_to,
- num);
+ Transform aligned_space[8];
+ BoundBox bounds[8];
+ int child[8];
+ for (int i = 0; i < num; ++i) {
+ aligned_space[i] = en[i].node->get_aligned_space();
+ bounds[i] = en[i].node->bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_unaligned_node(e.idx,
+ aligned_space,
+ bounds,
+ child,
+ e.node->visibility,
+ e.node->time_from,
+ e.node->time_to,
+ num);
}
void BVH8::pack_unaligned_node(int idx,
@@ -279,283 +265,275 @@ void BVH8::pack_unaligned_node(int idx,
const float time_to,
const int num)
{
- float8 data[BVH_UNALIGNED_ONODE_SIZE];
- memset(data, 0, sizeof(data));
+ float8 data[BVH_UNALIGNED_ONODE_SIZE];
+ memset(data, 0, sizeof(data));
- data[0].a = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED);
- data[0].b = time_from;
- data[0].c = time_to;
+ data[0].a = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED);
+ data[0].b = time_from;
+ data[0].c = time_to;
- for(int i = 0; i < num; i++) {
- Transform space = BVHUnaligned::compute_node_transform(
- bounds[i],
- aligned_space[i]);
+ for (int i = 0; i < num; i++) {
+ Transform space = BVHUnaligned::compute_node_transform(bounds[i], aligned_space[i]);
- data[1][i] = space.x.x;
- data[2][i] = space.x.y;
- data[3][i] = space.x.z;
+ data[1][i] = space.x.x;
+ data[2][i] = space.x.y;
+ data[3][i] = space.x.z;
- data[4][i] = space.y.x;
- data[5][i] = space.y.y;
- data[6][i] = space.y.z;
+ data[4][i] = space.y.x;
+ data[5][i] = space.y.y;
+ data[6][i] = space.y.z;
- data[7][i] = space.z.x;
- data[8][i] = space.z.y;
- data[9][i] = space.z.z;
+ data[7][i] = space.z.x;
+ data[8][i] = space.z.y;
+ data[9][i] = space.z.z;
- data[10][i] = space.x.w;
- data[11][i] = space.y.w;
- data[12][i] = space.z.w;
+ data[10][i] = space.x.w;
+ data[11][i] = space.y.w;
+ data[12][i] = space.z.w;
- data[13][i] = __int_as_float(child[i]);
- }
+ data[13][i] = __int_as_float(child[i]);
+ }
- for(int i = num; i < 8; i++) {
- /* We store BB which would never be recorded as intersection
- * so kernel might safely assume there are always 4 child nodes.
- */
+ for (int i = num; i < 8; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
- data[1][i] = NAN;
- data[2][i] = NAN;
- data[3][i] = NAN;
+ data[1][i] = NAN;
+ data[2][i] = NAN;
+ data[3][i] = NAN;
- data[4][i] = NAN;
- data[5][i] = NAN;
- data[6][i] = NAN;
+ data[4][i] = NAN;
+ data[5][i] = NAN;
+ data[6][i] = NAN;
- data[7][i] = NAN;
- data[8][i] = NAN;
- data[9][i] = NAN;
+ data[7][i] = NAN;
+ data[8][i] = NAN;
+ data[9][i] = NAN;
- data[10][i] = NAN;
- data[11][i] = NAN;
- data[12][i] = NAN;
+ data[10][i] = NAN;
+ data[11][i] = NAN;
+ data[12][i] = NAN;
- data[13][i] = __int_as_float(0);
- }
+ data[13][i] = __int_as_float(0);
+ }
- memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_ONODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(float4) * BVH_UNALIGNED_ONODE_SIZE);
}
/* Quad SIMD Nodes */
void BVH8::pack_nodes(const BVHNode *root)
{
- /* Calculate size of the arrays required. */
- const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
- const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- assert(num_leaf_nodes <= num_nodes);
- const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
- size_t node_size;
- if(params.use_unaligned_nodes) {
- const size_t num_unaligned_nodes =
- root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
- node_size = (num_unaligned_nodes * BVH_UNALIGNED_ONODE_SIZE) +
- (num_inner_nodes - num_unaligned_nodes) * BVH_ONODE_SIZE;
- }
- else {
- node_size = num_inner_nodes * BVH_ONODE_SIZE;
- }
- /* Resize arrays. */
- pack.nodes.clear();
- pack.leaf_nodes.clear();
- /* For top level BVH, first merge existing BVH's so we know the offsets. */
- if(params.top_level) {
- pack_instances(node_size, num_leaf_nodes*BVH_ONODE_LEAF_SIZE);
- }
- else {
- pack.nodes.resize(node_size);
- pack.leaf_nodes.resize(num_leaf_nodes*BVH_ONODE_LEAF_SIZE);
- }
-
- int nextNodeIdx = 0, nextLeafNodeIdx = 0;
-
- vector<BVHStackEntry> stack;
- stack.reserve(BVHParams::MAX_DEPTH*2);
- if(root->is_leaf()) {
- stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
- }
- else {
- stack.push_back(BVHStackEntry(root, nextNodeIdx));
- nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_ONODE_SIZE
- : BVH_ONODE_SIZE;
- }
-
- while(stack.size()) {
- BVHStackEntry e = stack.back();
- stack.pop_back();
-
- if(e.node->is_leaf()) {
- /* leaf node */
- const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
- pack_leaf(e, leaf);
- }
- else {
- /* Inner node. */
- /* Collect nodes. */
- const BVHNode *children[8];
- int num_children = e.node->num_children();
- /* Push entries on the stack. */
- for(int i = 0; i < num_children; ++i) {
- int idx;
- children[i] = e.node->get_child(i);
- if(children[i]->is_leaf()) {
- idx = nextLeafNodeIdx++;
- }
- else {
- idx = nextNodeIdx;
- nextNodeIdx += children[i]->has_unaligned()
- ? BVH_UNALIGNED_ONODE_SIZE
- : BVH_ONODE_SIZE;
- }
- stack.push_back(BVHStackEntry(children[i], idx));
- }
- /* Set node. */
- pack_inner(e, &stack[stack.size() - num_children], num_children);
- }
- }
-
- assert(node_size == nextNodeIdx);
- /* Root index to start traversal at, to handle case of single leaf node. */
- pack.root_index = (root->is_leaf()) ? -1 : 0;
+ /* Calculate size of the arrays required. */
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if (params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes = root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_ONODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_ONODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_ONODE_SIZE;
+ }
+ /* Resize arrays. */
+ pack.nodes.clear();
+ pack.leaf_nodes.clear();
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
+ if (params.top_level) {
+ pack_instances(node_size, num_leaf_nodes * BVH_ONODE_LEAF_SIZE);
+ }
+ else {
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes * BVH_ONODE_LEAF_SIZE);
+ }
+
+ int nextNodeIdx = 0, nextLeafNodeIdx = 0;
+
+ vector<BVHStackEntry> stack;
+ stack.reserve(BVHParams::MAX_DEPTH * 2);
+ if (root->is_leaf()) {
+ stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += root->has_unaligned() ? BVH_UNALIGNED_ONODE_SIZE : BVH_ONODE_SIZE;
+ }
+
+ while (stack.size()) {
+ BVHStackEntry e = stack.back();
+ stack.pop_back();
+
+ if (e.node->is_leaf()) {
+ /* leaf node */
+ const LeafNode *leaf = reinterpret_cast<const LeafNode *>(e.node);
+ pack_leaf(e, leaf);
+ }
+ else {
+ /* Inner node. */
+ /* Collect nodes. */
+ const BVHNode *children[8];
+ int num_children = e.node->num_children();
+ /* Push entries on the stack. */
+ for (int i = 0; i < num_children; ++i) {
+ int idx;
+ children[i] = e.node->get_child(i);
+ if (children[i]->is_leaf()) {
+ idx = nextLeafNodeIdx++;
+ }
+ else {
+ idx = nextNodeIdx;
+ nextNodeIdx += children[i]->has_unaligned() ? BVH_UNALIGNED_ONODE_SIZE : BVH_ONODE_SIZE;
+ }
+ stack.push_back(BVHStackEntry(children[i], idx));
+ }
+ /* Set node. */
+ pack_inner(e, &stack[stack.size() - num_children], num_children);
+ }
+ }
+
+ assert(node_size == nextNodeIdx);
+ /* Root index to start traversal at, to handle case of single leaf node. */
+ pack.root_index = (root->is_leaf()) ? -1 : 0;
}
void BVH8::refit_nodes()
{
- assert(!params.top_level);
+ assert(!params.top_level);
- BoundBox bbox = BoundBox::empty;
- uint visibility = 0;
- refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility);
+ BoundBox bbox = BoundBox::empty;
+ uint visibility = 0;
+ refit_node(0, (pack.root_index == -1) ? true : false, bbox, visibility);
}
-void BVH8::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
+void BVH8::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
{
- if(leaf) {
- int4 *data = &pack.leaf_nodes[idx];
- int4 c = data[0];
- /* Refit leaf node. */
- for(int prim = c.x; prim < c.y; prim++) {
- int pidx = pack.prim_index[prim];
- int tob = pack.prim_object[prim];
- Object *ob = objects[tob];
-
- if(pidx == -1) {
- /* Object instance. */
- bbox.grow(ob->bounds);
- }
- else {
- /* Primitives. */
- const Mesh *mesh = ob->mesh;
-
- if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
- /* Curves. */
- int str_offset = (params.top_level) ? mesh->curve_offset : 0;
- Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
- int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
-
- curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
-
- visibility |= PATH_RAY_CURVE;
-
- /* Motion curves. */
- if(mesh->use_motion_blur) {
- Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if(attr) {
- size_t mesh_size = mesh->curve_keys.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *key_steps = attr->data_float3();
-
- for(size_t i = 0; i < steps; i++) {
- curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
- }
- }
- }
- }
- else {
- /* Triangles. */
- int tri_offset = (params.top_level) ? mesh->tri_offset : 0;
- Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
- const float3 *vpos = &mesh->verts[0];
-
- triangle.bounds_grow(vpos, bbox);
-
- /* Motion triangles. */
- if(mesh->use_motion_blur) {
- Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if(attr) {
- size_t mesh_size = mesh->verts.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *vert_steps = attr->data_float3();
-
- for(size_t i = 0; i < steps; i++) {
- triangle.bounds_grow(vert_steps + i*mesh_size, bbox);
- }
- }
- }
- }
- }
-
- visibility |= ob->visibility;
- }
-
- float4 leaf_data[BVH_ONODE_LEAF_SIZE];
- leaf_data[0].x = __int_as_float(c.x);
- leaf_data[0].y = __int_as_float(c.y);
- leaf_data[0].z = __uint_as_float(visibility);
- leaf_data[0].w = __uint_as_float(c.w);
- memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_ONODE_LEAF_SIZE);
- }
- else {
- float8 *data = (float8*)&pack.nodes[idx];
- bool is_unaligned = (__float_as_uint(data[0].a) & PATH_RAY_NODE_UNALIGNED) != 0;
- /* Refit inner node, set bbox from children. */
- BoundBox child_bbox[8] = { BoundBox::empty, BoundBox::empty,
- BoundBox::empty, BoundBox::empty,
- BoundBox::empty, BoundBox::empty,
- BoundBox::empty, BoundBox::empty };
- int child[8];
- uint child_visibility[8] = { 0 };
- int num_nodes = 0;
-
- for(int i = 0; i < 8; ++i) {
- child[i] = __float_as_int(data[(is_unaligned) ? 13: 7][i]);
-
- if(child[i] != 0) {
- refit_node((child[i] < 0)? -child[i]-1: child[i], (child[i] < 0),
- child_bbox[i], child_visibility[i]);
- ++num_nodes;
- bbox.grow(child_bbox[i]);
- visibility |= child_visibility[i];
- }
- }
-
- if(is_unaligned) {
- Transform aligned_space[8] = { transform_identity(), transform_identity(),
- transform_identity(), transform_identity(),
- transform_identity(), transform_identity(),
- transform_identity(), transform_identity()};
- pack_unaligned_node(idx,
- aligned_space,
- child_bbox,
- child,
- visibility,
- 0.0f,
- 1.0f,
- num_nodes);
- }
- else {
- pack_aligned_node(idx,
- child_bbox,
- child,
- visibility,
- 0.0f,
- 1.0f,
- num_nodes);
- }
- }
+ if (leaf) {
+ int4 *data = &pack.leaf_nodes[idx];
+ int4 c = data[0];
+ /* Refit leaf node. */
+ for (int prim = c.x; prim < c.y; prim++) {
+ int pidx = pack.prim_index[prim];
+ int tob = pack.prim_object[prim];
+ Object *ob = objects[tob];
+
+ if (pidx == -1) {
+ /* Object instance. */
+ bbox.grow(ob->bounds);
+ }
+ else {
+ /* Primitives. */
+ const Mesh *mesh = ob->mesh;
+
+ if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
+ /* Curves. */
+ int str_offset = (params.top_level) ? mesh->curve_offset : 0;
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
+ int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
+
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
+
+ visibility |= PATH_RAY_CURVE;
+
+ /* Motion curves. */
+ if (mesh->use_motion_blur) {
+ Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t mesh_size = mesh->curve_keys.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *key_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++) {
+ curve.bounds_grow(k, key_steps + i * mesh_size, &mesh->curve_radius[0], bbox);
+ }
+ }
+ }
+ }
+ else {
+ /* Triangles. */
+ int tri_offset = (params.top_level) ? mesh->tri_offset : 0;
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
+ const float3 *vpos = &mesh->verts[0];
+
+ triangle.bounds_grow(vpos, bbox);
+
+ /* Motion triangles. */
+ if (mesh->use_motion_blur) {
+ Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t mesh_size = mesh->verts.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++) {
+ triangle.bounds_grow(vert_steps + i * mesh_size, bbox);
+ }
+ }
+ }
+ }
+ }
+
+ visibility |= ob->visibility;
+ }
+
+ float4 leaf_data[BVH_ONODE_LEAF_SIZE];
+ leaf_data[0].x = __int_as_float(c.x);
+ leaf_data[0].y = __int_as_float(c.y);
+ leaf_data[0].z = __uint_as_float(visibility);
+ leaf_data[0].w = __uint_as_float(c.w);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4) * BVH_ONODE_LEAF_SIZE);
+ }
+ else {
+ float8 *data = (float8 *)&pack.nodes[idx];
+ bool is_unaligned = (__float_as_uint(data[0].a) & PATH_RAY_NODE_UNALIGNED) != 0;
+ /* Refit inner node, set bbox from children. */
+ BoundBox child_bbox[8] = {BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty,
+ BoundBox::empty};
+ int child[8];
+ uint child_visibility[8] = {0};
+ int num_nodes = 0;
+
+ for (int i = 0; i < 8; ++i) {
+ child[i] = __float_as_int(data[(is_unaligned) ? 13 : 7][i]);
+
+ if (child[i] != 0) {
+ refit_node((child[i] < 0) ? -child[i] - 1 : child[i],
+ (child[i] < 0),
+ child_bbox[i],
+ child_visibility[i]);
+ ++num_nodes;
+ bbox.grow(child_bbox[i]);
+ visibility |= child_visibility[i];
+ }
+ }
+
+ if (is_unaligned) {
+ Transform aligned_space[8] = {transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity()};
+ pack_unaligned_node(
+ idx, aligned_space, child_bbox, child, visibility, 0.0f, 1.0f, num_nodes);
+ }
+ else {
+ pack_aligned_node(idx, child_bbox, child, visibility, 0.0f, 1.0f, num_nodes);
+ }
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh8.h b/intern/cycles/bvh/bvh8.h
index 277e2f2d653..fc07eadcada 100644
--- a/intern/cycles/bvh/bvh8.h
+++ b/intern/cycles/bvh/bvh8.h
@@ -45,8 +45,8 @@ class LeafNode;
class Object;
class Progress;
-#define BVH_ONODE_SIZE 16
-#define BVH_ONODE_LEAF_SIZE 1
+#define BVH_ONODE_SIZE 16
+#define BVH_ONODE_LEAF_SIZE 1
#define BVH_UNALIGNED_ONODE_SIZE 28
/* BVH8
@@ -54,48 +54,44 @@ class Progress;
* Octo BVH, with each node having eight children, to use with SIMD instructions.
*/
class BVH8 : public BVH {
-protected:
- /* constructor */
- friend class BVH;
- BVH8(const BVHParams& params, const vector<Object*>& objects);
+ protected:
+ /* constructor */
+ friend class BVH;
+ BVH8(const BVHParams &params, const vector<Object *> &objects);
- /* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+ /* Building process. */
+ virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
- /* pack */
- void pack_nodes(const BVHNode *root) override;
+ /* pack */
+ void pack_nodes(const BVHNode *root) override;
- void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
- void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
+ void pack_leaf(const BVHStackEntry &e, const LeafNode *leaf);
+ void pack_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
- void pack_aligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num);
- void pack_aligned_node(int idx,
- const BoundBox *bounds,
- const int *child,
- const uint visibility,
- const float time_from,
- const float time_to,
- const int num);
+ void pack_aligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
+ void pack_aligned_node(int idx,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const float time_from,
+ const float time_to,
+ const int num);
- void pack_unaligned_inner(const BVHStackEntry& e,
- const BVHStackEntry *en,
- int num);
- void pack_unaligned_node(int idx,
- const Transform *aligned_space,
- const BoundBox *bounds,
- const int *child,
- const uint visibility,
- const float time_from,
- const float time_to,
- const int num);
+ void pack_unaligned_inner(const BVHStackEntry &e, const BVHStackEntry *en, int num);
+ void pack_unaligned_node(int idx,
+ const Transform *aligned_space,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const float time_from,
+ const float time_to,
+ const int num);
- /* refit */
- void refit_nodes() override;
- void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
+ /* refit */
+ void refit_nodes() override;
+ void refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility);
};
CCL_NAMESPACE_END
-#endif /* __BVH8_H__ */
+#endif /* __BVH8_H__ */
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
index f574f31b358..d51143c578e 100644
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ b/intern/cycles/bvh/bvh_binning.cpp
@@ -29,225 +29,265 @@ CCL_NAMESPACE_BEGIN
/* SSE replacements */
-__forceinline void prefetch_L1 (const void* /*ptr*/) { }
-__forceinline void prefetch_L2 (const void* /*ptr*/) { }
-__forceinline void prefetch_L3 (const void* /*ptr*/) { }
-__forceinline void prefetch_NTA(const void* /*ptr*/) { }
+__forceinline void prefetch_L1(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_L2(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_L3(const void * /*ptr*/)
+{
+}
+__forceinline void prefetch_NTA(const void * /*ptr*/)
+{
+}
-template<size_t src> __forceinline float extract(const int4& b)
-{ return b[src]; }
-template<size_t dst> __forceinline const float4 insert(const float4& a, const float b)
-{ float4 r = a; r[dst] = b; return r; }
+template<size_t src> __forceinline float extract(const int4 &b)
+{
+ return b[src];
+}
+template<size_t dst> __forceinline const float4 insert(const float4 &a, const float b)
+{
+ float4 r = a;
+ r[dst] = b;
+ return r;
+}
-__forceinline int get_best_dimension(const float4& bestSAH)
+__forceinline int get_best_dimension(const float4 &bestSAH)
{
- // return (int)__bsf(movemask(reduce_min(bestSAH) == bestSAH));
+ // return (int)__bsf(movemask(reduce_min(bestSAH) == bestSAH));
- float minSAH = min(bestSAH.x, min(bestSAH.y, bestSAH.z));
+ float minSAH = min(bestSAH.x, min(bestSAH.y, bestSAH.z));
- if(bestSAH.x == minSAH) return 0;
- else if(bestSAH.y == minSAH) return 1;
- else return 2;
+ if (bestSAH.x == minSAH)
+ return 0;
+ else if (bestSAH.y == minSAH)
+ return 1;
+ else
+ return 2;
}
/* BVH Object Binning */
-BVHObjectBinning::BVHObjectBinning(const BVHRange& job,
+BVHObjectBinning::BVHObjectBinning(const BVHRange &job,
BVHReference *prims,
const BVHUnaligned *unaligned_heuristic,
const Transform *aligned_space)
-: BVHRange(job),
- splitSAH(FLT_MAX),
- dim(0),
- pos(0),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
+ : BVHRange(job),
+ splitSAH(FLT_MAX),
+ dim(0),
+ pos(0),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
- if(aligned_space_ == NULL) {
- bounds_ = bounds();
- cent_bounds_ = cent_bounds();
- }
- else {
- /* TODO(sergey): With some additional storage we can avoid
- * need in re-calculating this.
- */
- bounds_ = unaligned_heuristic->compute_aligned_boundbox(
- *this,
- prims,
- *aligned_space,
- &cent_bounds_);
- }
-
- /* compute number of bins to use and precompute scaling factor for binning */
- num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f*size()));
- scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
-
- /* initialize binning counter and bounds */
- BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
- int4 bin_count[MAX_BINS]; /* number of primitives mapped to bin */
-
- for(size_t i = 0; i < num_bins; i++) {
- bin_count[i] = make_int4(0);
- bin_bounds[i][0] = bin_bounds[i][1] = bin_bounds[i][2] = BoundBox::empty;
- }
-
- /* map geometry to bins, unrolled once */
- {
- ssize_t i;
-
- for(i = 0; i < ssize_t(size()) - 1; i += 2) {
- prefetch_L2(&prims[start() + i + 8]);
-
- /* map even and odd primitive to bin */
- const BVHReference& prim0 = prims[start() + i + 0];
- const BVHReference& prim1 = prims[start() + i + 1];
-
- BoundBox bounds0 = get_prim_bounds(prim0);
- BoundBox bounds1 = get_prim_bounds(prim1);
-
- int4 bin0 = get_bin(bounds0);
- int4 bin1 = get_bin(bounds1);
-
- /* increase bounds for bins for even primitive */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
-
- /* increase bounds of bins for odd primitive */
- int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(bounds1);
- int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(bounds1);
- int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(bounds1);
- }
-
- /* for uneven number of primitives */
- if(i < ssize_t(size())) {
- /* map primitive to bin */
- const BVHReference& prim0 = prims[start() + i];
- BoundBox bounds0 = get_prim_bounds(prim0);
- int4 bin0 = get_bin(bounds0);
-
- /* increase bounds of bins */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
- }
- }
-
- /* sweep from right to left and compute parallel prefix of merged bounds */
- float4 r_area[MAX_BINS]; /* area of bounds of primitives on the right */
- float4 r_count[MAX_BINS]; /* number of primitives on the right */
- int4 count = make_int4(0);
-
- BoundBox bx = BoundBox::empty;
- BoundBox by = BoundBox::empty;
- BoundBox bz = BoundBox::empty;
-
- for(size_t i = num_bins - 1; i > 0; i--) {
- count = count + bin_count[i];
- r_count[i] = blocks(count);
-
- bx = merge(bx,bin_bounds[i][0]); r_area[i][0] = bx.half_area();
- by = merge(by,bin_bounds[i][1]); r_area[i][1] = by.half_area();
- bz = merge(bz,bin_bounds[i][2]); r_area[i][2] = bz.half_area();
- r_area[i][3] = r_area[i][2];
- }
-
- /* sweep from left to right and compute SAH */
- int4 ii = make_int4(1);
- float4 bestSAH = make_float4(FLT_MAX);
- int4 bestSplit = make_int4(-1);
-
- count = make_int4(0);
-
- bx = BoundBox::empty;
- by = BoundBox::empty;
- bz = BoundBox::empty;
-
- for(size_t i = 1; i < num_bins; i++, ii += make_int4(1)) {
- count = count + bin_count[i-1];
-
- bx = merge(bx,bin_bounds[i-1][0]); float Ax = bx.half_area();
- by = merge(by,bin_bounds[i-1][1]); float Ay = by.half_area();
- bz = merge(bz,bin_bounds[i-1][2]); float Az = bz.half_area();
-
- float4 lCount = blocks(count);
- float4 lArea = make_float4(Ax,Ay,Az,Az);
- float4 sah = lArea*lCount + r_area[i]*r_count[i];
-
- bestSplit = select(sah < bestSAH,ii,bestSplit);
- bestSAH = min(sah,bestSAH);
- }
-
- int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
- bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
-
- /* find best dimension */
- dim = get_best_dimension(bestSAH);
- splitSAH = bestSAH[dim];
- pos = bestSplit[dim];
- leafSAH = bounds_.half_area() * blocks(size());
+ if (aligned_space_ == NULL) {
+ bounds_ = bounds();
+ cent_bounds_ = cent_bounds();
+ }
+ else {
+ /* TODO(sergey): With some additional storage we can avoid
+ * need in re-calculating this.
+ */
+ bounds_ = unaligned_heuristic->compute_aligned_boundbox(
+ *this, prims, *aligned_space, &cent_bounds_);
+ }
+
+ /* compute number of bins to use and precompute scaling factor for binning */
+ num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f * size()));
+ scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
+
+ /* initialize binning counter and bounds */
+ BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
+ int4 bin_count[MAX_BINS]; /* number of primitives mapped to bin */
+
+ for (size_t i = 0; i < num_bins; i++) {
+ bin_count[i] = make_int4(0);
+ bin_bounds[i][0] = bin_bounds[i][1] = bin_bounds[i][2] = BoundBox::empty;
+ }
+
+ /* map geometry to bins, unrolled once */
+ {
+ ssize_t i;
+
+ for (i = 0; i < ssize_t(size()) - 1; i += 2) {
+ prefetch_L2(&prims[start() + i + 8]);
+
+ /* map even and odd primitive to bin */
+ const BVHReference &prim0 = prims[start() + i + 0];
+ const BVHReference &prim1 = prims[start() + i + 1];
+
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ BoundBox bounds1 = get_prim_bounds(prim1);
+
+ int4 bin0 = get_bin(bounds0);
+ int4 bin1 = get_bin(bounds1);
+
+ /* increase bounds for bins for even primitive */
+ int b00 = (int)extract<0>(bin0);
+ bin_count[b00][0]++;
+ bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0);
+ bin_count[b01][1]++;
+ bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0);
+ bin_count[b02][2]++;
+ bin_bounds[b02][2].grow(bounds0);
+
+ /* increase bounds of bins for odd primitive */
+ int b10 = (int)extract<0>(bin1);
+ bin_count[b10][0]++;
+ bin_bounds[b10][0].grow(bounds1);
+ int b11 = (int)extract<1>(bin1);
+ bin_count[b11][1]++;
+ bin_bounds[b11][1].grow(bounds1);
+ int b12 = (int)extract<2>(bin1);
+ bin_count[b12][2]++;
+ bin_bounds[b12][2].grow(bounds1);
+ }
+
+ /* for uneven number of primitives */
+ if (i < ssize_t(size())) {
+ /* map primitive to bin */
+ const BVHReference &prim0 = prims[start() + i];
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ int4 bin0 = get_bin(bounds0);
+
+ /* increase bounds of bins */
+ int b00 = (int)extract<0>(bin0);
+ bin_count[b00][0]++;
+ bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0);
+ bin_count[b01][1]++;
+ bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0);
+ bin_count[b02][2]++;
+ bin_bounds[b02][2].grow(bounds0);
+ }
+ }
+
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ float4 r_area[MAX_BINS]; /* area of bounds of primitives on the right */
+ float4 r_count[MAX_BINS]; /* number of primitives on the right */
+ int4 count = make_int4(0);
+
+ BoundBox bx = BoundBox::empty;
+ BoundBox by = BoundBox::empty;
+ BoundBox bz = BoundBox::empty;
+
+ for (size_t i = num_bins - 1; i > 0; i--) {
+ count = count + bin_count[i];
+ r_count[i] = blocks(count);
+
+ bx = merge(bx, bin_bounds[i][0]);
+ r_area[i][0] = bx.half_area();
+ by = merge(by, bin_bounds[i][1]);
+ r_area[i][1] = by.half_area();
+ bz = merge(bz, bin_bounds[i][2]);
+ r_area[i][2] = bz.half_area();
+ r_area[i][3] = r_area[i][2];
+ }
+
+ /* sweep from left to right and compute SAH */
+ int4 ii = make_int4(1);
+ float4 bestSAH = make_float4(FLT_MAX);
+ int4 bestSplit = make_int4(-1);
+
+ count = make_int4(0);
+
+ bx = BoundBox::empty;
+ by = BoundBox::empty;
+ bz = BoundBox::empty;
+
+ for (size_t i = 1; i < num_bins; i++, ii += make_int4(1)) {
+ count = count + bin_count[i - 1];
+
+ bx = merge(bx, bin_bounds[i - 1][0]);
+ float Ax = bx.half_area();
+ by = merge(by, bin_bounds[i - 1][1]);
+ float Ay = by.half_area();
+ bz = merge(bz, bin_bounds[i - 1][2]);
+ float Az = bz.half_area();
+
+ float4 lCount = blocks(count);
+ float4 lArea = make_float4(Ax, Ay, Az, Az);
+ float4 sah = lArea * lCount + r_area[i] * r_count[i];
+
+ bestSplit = select(sah < bestSAH, ii, bestSplit);
+ bestSAH = min(sah, bestSAH);
+ }
+
+ int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
+ bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
+
+ /* find best dimension */
+ dim = get_best_dimension(bestSAH);
+ splitSAH = bestSAH[dim];
+ pos = bestSplit[dim];
+ leafSAH = bounds_.half_area() * blocks(size());
}
-void BVHObjectBinning::split(BVHReference* prims,
- BVHObjectBinning& left_o,
- BVHObjectBinning& right_o) const
+void BVHObjectBinning::split(BVHReference *prims,
+ BVHObjectBinning &left_o,
+ BVHObjectBinning &right_o) const
{
- size_t N = size();
-
- BoundBox lgeom_bounds = BoundBox::empty;
- BoundBox rgeom_bounds = BoundBox::empty;
- BoundBox lcent_bounds = BoundBox::empty;
- BoundBox rcent_bounds = BoundBox::empty;
-
- ssize_t l = 0, r = N-1;
-
- while(l <= r) {
- prefetch_L2(&prims[start() + l + 8]);
- prefetch_L2(&prims[start() + r - 8]);
-
- BVHReference prim = prims[start() + l];
- BoundBox unaligned_bounds = get_prim_bounds(prim);
- float3 unaligned_center = unaligned_bounds.center2();
- float3 center = prim.bounds().center2();
-
- if(get_bin(unaligned_center)[dim] < pos) {
- lgeom_bounds.grow(prim.bounds());
- lcent_bounds.grow(center);
- l++;
- }
- else {
- rgeom_bounds.grow(prim.bounds());
- rcent_bounds.grow(center);
- swap(prims[start()+l],prims[start()+r]);
- r--;
- }
- }
- /* finish */
- if(l != 0 && N-1-r != 0) {
- right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N-1-r), prims);
- left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), l), prims);
- return;
- }
-
- /* object medium split if we did not make progress, can happen when all
- * primitives have same centroid */
- lgeom_bounds = BoundBox::empty;
- rgeom_bounds = BoundBox::empty;
- lcent_bounds = BoundBox::empty;
- rcent_bounds = BoundBox::empty;
-
- for(size_t i = 0; i < N/2; i++) {
- lgeom_bounds.grow(prims[start()+i].bounds());
- lcent_bounds.grow(prims[start()+i].bounds().center2());
- }
-
- for(size_t i = N/2; i < N; i++) {
- rgeom_bounds.grow(prims[start()+i].bounds());
- rcent_bounds.grow(prims[start()+i].bounds().center2());
- }
-
- right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + N/2, N/2 + N%2), prims);
- left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), N/2), prims);
+ size_t N = size();
+
+ BoundBox lgeom_bounds = BoundBox::empty;
+ BoundBox rgeom_bounds = BoundBox::empty;
+ BoundBox lcent_bounds = BoundBox::empty;
+ BoundBox rcent_bounds = BoundBox::empty;
+
+ ssize_t l = 0, r = N - 1;
+
+ while (l <= r) {
+ prefetch_L2(&prims[start() + l + 8]);
+ prefetch_L2(&prims[start() + r - 8]);
+
+ BVHReference prim = prims[start() + l];
+ BoundBox unaligned_bounds = get_prim_bounds(prim);
+ float3 unaligned_center = unaligned_bounds.center2();
+ float3 center = prim.bounds().center2();
+
+ if (get_bin(unaligned_center)[dim] < pos) {
+ lgeom_bounds.grow(prim.bounds());
+ lcent_bounds.grow(center);
+ l++;
+ }
+ else {
+ rgeom_bounds.grow(prim.bounds());
+ rcent_bounds.grow(center);
+ swap(prims[start() + l], prims[start() + r]);
+ r--;
+ }
+ }
+ /* finish */
+ if (l != 0 && N - 1 - r != 0) {
+ right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N - 1 - r),
+ prims);
+ left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), l), prims);
+ return;
+ }
+
+ /* object medium split if we did not make progress, can happen when all
+ * primitives have same centroid */
+ lgeom_bounds = BoundBox::empty;
+ rgeom_bounds = BoundBox::empty;
+ lcent_bounds = BoundBox::empty;
+ rcent_bounds = BoundBox::empty;
+
+ for (size_t i = 0; i < N / 2; i++) {
+ lgeom_bounds.grow(prims[start() + i].bounds());
+ lcent_bounds.grow(prims[start() + i].bounds().center2());
+ }
+
+ for (size_t i = N / 2; i < N; i++) {
+ rgeom_bounds.grow(prims[start() + i].bounds());
+ rcent_bounds.grow(prims[start() + i].bounds().center2());
+ }
+
+ right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + N / 2, N / 2 + N % 2),
+ prims);
+ left_o = BVHObjectBinning(BVHRange(lgeom_bounds, lcent_bounds, start(), N / 2), prims);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h
index c2e259b1696..ae6dba2805d 100644
--- a/intern/cycles/bvh/bvh_binning.h
+++ b/intern/cycles/bvh/bvh_binning.h
@@ -34,81 +34,82 @@ class BVHBuild;
* location to different sets. The SAH is evaluated by computing the number of
* blocks occupied by the primitives in the partitions. */
-class BVHObjectBinning : public BVHRange
-{
-public:
- __forceinline BVHObjectBinning() : leafSAH(FLT_MAX) {}
-
- BVHObjectBinning(const BVHRange& job,
- BVHReference *prims,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHReference *prims,
- BVHObjectBinning& left_o,
- BVHObjectBinning& right_o) const;
-
- __forceinline const BoundBox& unaligned_bounds() { return bounds_; }
-
- float splitSAH; /* SAH cost of the best split */
- float leafSAH; /* SAH cost of creating a leaf */
-
-protected:
- int dim; /* best split dimension */
- int pos; /* best split position */
- size_t num_bins; /* actual number of bins to use */
- float3 scale; /* scaling factor to compute bin */
-
- /* Effective bounds and centroid bounds. */
- BoundBox bounds_;
- BoundBox cent_bounds_;
-
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- enum { MAX_BINS = 32 };
- enum { LOG_BLOCK_SIZE = 2 };
-
- /* computes the bin numbers for each dimension for a box. */
- __forceinline int4 get_bin(const BoundBox& box) const
- {
- int4 a = make_int4((box.center2() - cent_bounds_.min)*scale - make_float3(0.5f));
- int4 mn = make_int4(0);
- int4 mx = make_int4((int)num_bins-1);
-
- return clamp(a, mn, mx);
- }
-
- /* computes the bin numbers for each dimension for a point. */
- __forceinline int4 get_bin(const float3& c) const
- {
- return make_int4((c - cent_bounds_.min)*scale - make_float3(0.5f));
- }
-
- /* compute the number of blocks occupied for each dimension. */
- __forceinline float4 blocks(const int4& a) const
- {
- return make_float4((a + make_int4((1 << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE);
- }
-
- /* compute the number of blocks occupied in one dimension. */
- __forceinline int blocks(size_t a) const
- {
- return (int)((a+((1LL << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE);
- }
-
- __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
- {
- if(aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(
- prim, *aligned_space_);
- }
- }
+class BVHObjectBinning : public BVHRange {
+ public:
+ __forceinline BVHObjectBinning() : leafSAH(FLT_MAX)
+ {
+ }
+
+ BVHObjectBinning(const BVHRange &job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHReference *prims, BVHObjectBinning &left_o, BVHObjectBinning &right_o) const;
+
+ __forceinline const BoundBox &unaligned_bounds()
+ {
+ return bounds_;
+ }
+
+ float splitSAH; /* SAH cost of the best split */
+ float leafSAH; /* SAH cost of creating a leaf */
+
+ protected:
+ int dim; /* best split dimension */
+ int pos; /* best split position */
+ size_t num_bins; /* actual number of bins to use */
+ float3 scale; /* scaling factor to compute bin */
+
+ /* Effective bounds and centroid bounds. */
+ BoundBox bounds_;
+ BoundBox cent_bounds_;
+
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ enum { MAX_BINS = 32 };
+ enum { LOG_BLOCK_SIZE = 2 };
+
+ /* computes the bin numbers for each dimension for a box. */
+ __forceinline int4 get_bin(const BoundBox &box) const
+ {
+ int4 a = make_int4((box.center2() - cent_bounds_.min) * scale - make_float3(0.5f));
+ int4 mn = make_int4(0);
+ int4 mx = make_int4((int)num_bins - 1);
+
+ return clamp(a, mn, mx);
+ }
+
+ /* computes the bin numbers for each dimension for a point. */
+ __forceinline int4 get_bin(const float3 &c) const
+ {
+ return make_int4((c - cent_bounds_.min) * scale - make_float3(0.5f));
+ }
+
+ /* compute the number of blocks occupied for each dimension. */
+ __forceinline float4 blocks(const int4 &a) const
+ {
+ return make_float4((a + make_int4((1 << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
+ }
+
+ /* compute the number of blocks occupied in one dimension. */
+ __forceinline int blocks(size_t a) const
+ {
+ return (int)((a + ((1LL << LOG_BLOCK_SIZE) - 1)) >> LOG_BLOCK_SIZE);
+ }
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
};
CCL_NAMESPACE_END
-#endif /* __BVH_BINNING_H__ */
+#endif /* __BVH_BINNING_H__ */
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index c0b3d683e37..1d9b006e8cb 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -41,72 +41,65 @@ CCL_NAMESPACE_BEGIN
/* BVH Build Task */
class BVHBuildTask : public Task {
-public:
- BVHBuildTask(BVHBuild *build,
- InnerNode *node,
- int child,
- const BVHObjectBinning& range,
- int level)
- : range_(range)
- {
- run = function_bind(&BVHBuild::thread_build_node,
- build,
- node,
- child,
- &range_,
- level);
- }
-private:
- BVHObjectBinning range_;
+ public:
+ BVHBuildTask(
+ BVHBuild *build, InnerNode *node, int child, const BVHObjectBinning &range, int level)
+ : range_(range)
+ {
+ run = function_bind(&BVHBuild::thread_build_node, build, node, child, &range_, level);
+ }
+
+ private:
+ BVHObjectBinning range_;
};
class BVHSpatialSplitBuildTask : public Task {
-public:
- BVHSpatialSplitBuildTask(BVHBuild *build,
- InnerNode *node,
- int child,
- const BVHRange& range,
- const vector<BVHReference>& references,
- int level)
- : range_(range),
- references_(references.begin() + range.start(),
- references.begin() + range.end())
- {
- range_.set_start(0);
- run = function_bind(&BVHBuild::thread_build_spatial_split_node,
- build,
- node,
- child,
- &range_,
- &references_,
- level,
- _1);
- }
-private:
- BVHRange range_;
- vector<BVHReference> references_;
+ public:
+ BVHSpatialSplitBuildTask(BVHBuild *build,
+ InnerNode *node,
+ int child,
+ const BVHRange &range,
+ const vector<BVHReference> &references,
+ int level)
+ : range_(range),
+ references_(references.begin() + range.start(), references.begin() + range.end())
+ {
+ range_.set_start(0);
+ run = function_bind(&BVHBuild::thread_build_spatial_split_node,
+ build,
+ node,
+ child,
+ &range_,
+ &references_,
+ level,
+ _1);
+ }
+
+ private:
+ BVHRange range_;
+ vector<BVHReference> references_;
};
/* Constructor / Destructor */
-BVHBuild::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_)
- : objects(objects_),
- prim_type(prim_type_),
- prim_index(prim_index_),
- prim_object(prim_object_),
- prim_time(prim_time_),
- params(params_),
- progress(progress_),
- progress_start_time(0.0),
- unaligned_heuristic(objects_)
+BVHBuild::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_)
+ : objects(objects_),
+ prim_type(prim_type_),
+ prim_index(prim_index_),
+ prim_object(prim_object_),
+ prim_time(prim_time_),
+ params(params_),
+ progress(progress_),
+ progress_start_time(0.0),
+ unaligned_heuristic(objects_)
{
- spatial_min_overlap = 0.0f;
+ spatial_min_overlap = 0.0f;
}
BVHBuild::~BVHBuild()
@@ -115,467 +108,440 @@ BVHBuild::~BVHBuild()
/* Adding References */
-void BVHBuild::add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+void BVHBuild::add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i)
{
- const Attribute *attr_mP = NULL;
- if(mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- }
- const size_t num_triangles = mesh->num_triangles();
- for(uint j = 0; j < num_triangles; j++) {
- Mesh::Triangle t = mesh->get_triangle(j);
- const float3 *verts = &mesh->verts[0];
- if(attr_mP == NULL) {
- BoundBox bounds = BoundBox::empty;
- t.bounds_grow(verts, bounds);
- if(bounds.valid() && t.valid(verts)) {
- references.push_back(BVHReference(bounds,
- j,
- i,
- PRIMITIVE_TRIANGLE));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
- /* Motion triangles, simple case: single node for the whole
- * primitive. Lowest memory footprint and faster BVH build but
- * least optimal ray-tracing.
- */
- /* TODO(sergey): Support motion steps for spatially split BVH. */
- const size_t num_verts = mesh->verts.size();
- const size_t num_steps = mesh->motion_steps;
- const float3 *vert_steps = attr_mP->data_float3();
- BoundBox bounds = BoundBox::empty;
- t.bounds_grow(verts, bounds);
- for(size_t step = 0; step < num_steps - 1; step++) {
- t.bounds_grow(vert_steps + step*num_verts, bounds);
- }
- if(bounds.valid()) {
- references.push_back(
- BVHReference(bounds,
- j,
- i,
- PRIMITIVE_MOTION_TRIANGLE));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else {
- /* Motion triangles, trace optimized case: we split triangle
- * primitives into separate nodes for each of the time steps.
- * This way we minimize overlap of neighbor curve primitives.
- */
- const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
- const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
- const size_t num_verts = mesh->verts.size();
- const size_t num_steps = mesh->motion_steps;
- const float3 *vert_steps = attr_mP->data_float3();
- /* Calculate bounding box of the previous time step.
- * Will be reused later to avoid duplicated work on
- * calculating BVH time step boundbox.
- */
- float3 prev_verts[3];
- t.motion_verts(verts,
- vert_steps,
- num_verts,
- num_steps,
- 0.0f,
- prev_verts);
- BoundBox prev_bounds = BoundBox::empty;
- prev_bounds.grow(prev_verts[0]);
- prev_bounds.grow(prev_verts[1]);
- prev_bounds.grow(prev_verts[2]);
- /* Create all primitive time steps, */
- for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
- const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
- float3 curr_verts[3];
- t.motion_verts(verts,
- vert_steps,
- num_verts,
- num_steps,
- curr_time,
- curr_verts);
- BoundBox curr_bounds = BoundBox::empty;
- curr_bounds.grow(curr_verts[0]);
- curr_bounds.grow(curr_verts[1]);
- curr_bounds.grow(curr_verts[2]);
- BoundBox bounds = prev_bounds;
- bounds.grow(curr_bounds);
- if(bounds.valid()) {
- const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
- references.push_back(
- BVHReference(bounds,
- j,
- i,
- PRIMITIVE_MOTION_TRIANGLE,
- prev_time,
- curr_time));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- /* Current time boundbox becomes previous one for the
- * next time step.
- */
- prev_bounds = curr_bounds;
- }
- }
- }
+ const Attribute *attr_mP = NULL;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ const size_t num_triangles = mesh->num_triangles();
+ for (uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ const float3 *verts = &mesh->verts[0];
+ if (attr_mP == NULL) {
+ BoundBox bounds = BoundBox::empty;
+ t.bounds_grow(verts, bounds);
+ if (bounds.valid() && t.valid(verts)) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_TRIANGLE));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else if (params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
+ /* Motion triangles, simple case: single node for the whole
+ * primitive. Lowest memory footprint and faster BVH build but
+ * least optimal ray-tracing.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ BoundBox bounds = BoundBox::empty;
+ t.bounds_grow(verts, bounds);
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ t.bounds_grow(vert_steps + step * num_verts, bounds);
+ }
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_MOTION_TRIANGLE));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else {
+ /* Motion triangles, trace optimized case: we split triangle
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_verts = mesh->verts.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *vert_steps = attr_mP->data_float3();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float3 prev_verts[3];
+ t.motion_verts(verts, vert_steps, num_verts, num_steps, 0.0f, prev_verts);
+ BoundBox prev_bounds = BoundBox::empty;
+ prev_bounds.grow(prev_verts[0]);
+ prev_bounds.grow(prev_verts[1]);
+ prev_bounds.grow(prev_verts[2]);
+ /* Create all primitive time steps, */
+ for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
+ float3 curr_verts[3];
+ t.motion_verts(verts, vert_steps, num_verts, num_steps, curr_time, curr_verts);
+ BoundBox curr_bounds = BoundBox::empty;
+ curr_bounds.grow(curr_verts[0]);
+ curr_bounds.grow(curr_verts[1]);
+ curr_bounds.grow(curr_verts[2]);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if (bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ references.push_back(
+ BVHReference(bounds, j, i, PRIMITIVE_MOTION_TRIANGLE, prev_time, curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
+ }
}
-void BVHBuild::add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Mesh *mesh, int i)
{
- const Attribute *curve_attr_mP = NULL;
- if(mesh->has_motion_blur()) {
- curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- }
- const size_t num_curves = mesh->num_curves();
- for(uint j = 0; j < num_curves; j++) {
- const Mesh::Curve curve = mesh->get_curve(j);
- const float *curve_radius = &mesh->curve_radius[0];
- for(int k = 0; k < curve.num_keys - 1; k++) {
- if(curve_attr_mP == NULL) {
- /* Really simple logic for static hair. */
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
- if(bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k);
- references.push_back(BVHReference(bounds, j, i, packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) {
- /* Simple case of motion curves: single node for the while
- * shutter time. Lowest memory usage but less optimal
- * rendering.
- */
- /* TODO(sergey): Support motion steps for spatially split BVH. */
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
- const size_t num_keys = mesh->curve_keys.size();
- const size_t num_steps = mesh->motion_steps;
- const float3 *key_steps = curve_attr_mP->data_float3();
- for(size_t step = 0; step < num_steps - 1; step++) {
- curve.bounds_grow(k,
- key_steps + step*num_keys,
- curve_radius,
- bounds);
- }
- if(bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
- references.push_back(BVHReference(bounds,
- j,
- i,
- packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- }
- else {
- /* Motion curves, trace optimized case: we split curve keys
- * primitives into separate nodes for each of the time steps.
- * This way we minimize overlap of neighbor curve primitives.
- */
- const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
- const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
- const size_t num_steps = mesh->motion_steps;
- const float3 *curve_keys = &mesh->curve_keys[0];
- const float3 *key_steps = curve_attr_mP->data_float3();
- const size_t num_keys = mesh->curve_keys.size();
- /* Calculate bounding box of the previous time step.
- * Will be reused later to avoid duplicated work on
- * calculating BVH time step boundbox.
- */
- float4 prev_keys[4];
- curve.cardinal_motion_keys(curve_keys,
- curve_radius,
- key_steps,
- num_keys,
- num_steps,
- 0.0f,
- k - 1, k, k + 1, k + 2,
- prev_keys);
- BoundBox prev_bounds = BoundBox::empty;
- curve.bounds_grow(prev_keys, prev_bounds);
- /* Create all primitive time steps, */
- for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
- const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
- float4 curr_keys[4];
- curve.cardinal_motion_keys(curve_keys,
- curve_radius,
- key_steps,
- num_keys,
- num_steps,
- curr_time,
- k - 1, k, k + 1, k + 2,
- curr_keys);
- BoundBox curr_bounds = BoundBox::empty;
- curve.bounds_grow(curr_keys, curr_bounds);
- BoundBox bounds = prev_bounds;
- bounds.grow(curr_bounds);
- if(bounds.valid()) {
- const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
- int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
- references.push_back(BVHReference(bounds,
- j,
- i,
- packed_type,
- prev_time,
- curr_time));
- root.grow(bounds);
- center.grow(bounds.center2());
- }
- /* Current time boundbox becomes previous one for the
- * next time step.
- */
- prev_bounds = curr_bounds;
- }
- }
- }
- }
+ const Attribute *curve_attr_mP = NULL;
+ if (mesh->has_motion_blur()) {
+ curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ const size_t num_curves = mesh->num_curves();
+ for (uint j = 0; j < num_curves; j++) {
+ const Mesh::Curve curve = mesh->get_curve(j);
+ const float *curve_radius = &mesh->curve_radius[0];
+ for (int k = 0; k < curve.num_keys - 1; k++) {
+ if (curve_attr_mP == NULL) {
+ /* Really simple logic for static hair. */
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
+ if (bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k);
+ references.push_back(BVHReference(bounds, j, i, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else if (params.num_motion_curve_steps == 0 || params.use_spatial_split) {
+ /* Simple case of motion curves: single node for the while
+ * shutter time. Lowest memory usage but less optimal
+ * rendering.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
+ const size_t num_keys = mesh->curve_keys.size();
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds);
+ }
+ if (bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+ references.push_back(BVHReference(bounds, j, i, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ else {
+ /* Motion curves, trace optimized case: we split curve keys
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor curve primitives.
+ */
+ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+ const size_t num_steps = mesh->motion_steps;
+ const float3 *curve_keys = &mesh->curve_keys[0];
+ const float3 *key_steps = curve_attr_mP->data_float3();
+ const size_t num_keys = mesh->curve_keys.size();
+ /* Calculate bounding box of the previous time step.
+ * Will be reused later to avoid duplicated work on
+ * calculating BVH time step boundbox.
+ */
+ float4 prev_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ 0.0f,
+ k - 1,
+ k,
+ k + 1,
+ k + 2,
+ prev_keys);
+ BoundBox prev_bounds = BoundBox::empty;
+ curve.bounds_grow(prev_keys, prev_bounds);
+ /* Create all primitive time steps, */
+ for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+ const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
+ float4 curr_keys[4];
+ curve.cardinal_motion_keys(curve_keys,
+ curve_radius,
+ key_steps,
+ num_keys,
+ num_steps,
+ curr_time,
+ k - 1,
+ k,
+ k + 1,
+ k + 2,
+ curr_keys);
+ BoundBox curr_bounds = BoundBox::empty;
+ curve.bounds_grow(curr_keys, curr_bounds);
+ BoundBox bounds = prev_bounds;
+ bounds.grow(curr_bounds);
+ if (bounds.valid()) {
+ const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
+ int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+ references.push_back(BVHReference(bounds, j, i, packed_type, prev_time, curr_time));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ /* Current time boundbox becomes previous one for the
+ * next time step.
+ */
+ prev_bounds = curr_bounds;
+ }
+ }
+ }
+ }
}
-void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
+void BVHBuild::add_reference_mesh(BoundBox &root, BoundBox &center, Mesh *mesh, int i)
{
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
- add_reference_triangles(root, center, mesh, i);
- }
- if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
- add_reference_curves(root, center, mesh, i);
- }
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ add_reference_triangles(root, center, mesh, i);
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ add_reference_curves(root, center, mesh, i);
+ }
}
-void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i)
+void BVHBuild::add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i)
{
- references.push_back(BVHReference(ob->bounds, -1, i, 0));
- root.grow(ob->bounds);
- center.grow(ob->bounds.center2());
+ references.push_back(BVHReference(ob->bounds, -1, i, 0));
+ root.grow(ob->bounds);
+ center.grow(ob->bounds.center2());
}
static size_t count_curve_segments(Mesh *mesh)
{
- size_t num = 0, num_curves = mesh->num_curves();
+ size_t num = 0, num_curves = mesh->num_curves();
- for(size_t i = 0; i < num_curves; i++)
- num += mesh->get_curve(i).num_keys - 1;
+ for (size_t i = 0; i < num_curves; i++)
+ num += mesh->get_curve(i).num_keys - 1;
- return num;
+ return num;
}
-void BVHBuild::add_references(BVHRange& root)
+void BVHBuild::add_references(BVHRange &root)
{
- /* reserve space for references */
- size_t num_alloc_references = 0;
-
- foreach(Object *ob, objects) {
- if(params.top_level) {
- if(!ob->is_traceable()) {
- continue;
- }
- if(!ob->mesh->is_instanced()) {
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
- num_alloc_references += ob->mesh->num_triangles();
- }
- if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
- num_alloc_references += count_curve_segments(ob->mesh);
- }
- }
- else
- num_alloc_references++;
- }
- else {
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
- num_alloc_references += ob->mesh->num_triangles();
- }
- if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
- num_alloc_references += count_curve_segments(ob->mesh);
- }
- }
- }
-
- references.reserve(num_alloc_references);
-
- /* add references from objects */
- BoundBox bounds = BoundBox::empty, center = BoundBox::empty;
- int i = 0;
-
- foreach(Object *ob, objects) {
- if(params.top_level) {
- if(!ob->is_traceable()) {
- ++i;
- continue;
- }
- if(!ob->mesh->is_instanced())
- add_reference_mesh(bounds, center, ob->mesh, i);
- else
- add_reference_object(bounds, center, ob, i);
- }
- else
- add_reference_mesh(bounds, center, ob->mesh, i);
-
- i++;
-
- if(progress.get_cancel()) return;
- }
-
- /* happens mostly on empty meshes */
- if(!bounds.valid())
- bounds.grow(make_float3(0.0f, 0.0f, 0.0f));
-
- root = BVHRange(bounds, center, 0, references.size());
+ /* reserve space for references */
+ size_t num_alloc_references = 0;
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ continue;
+ }
+ if (!ob->mesh->is_instanced()) {
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
+ }
+ else
+ num_alloc_references++;
+ }
+ else {
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
+ }
+ }
+
+ references.reserve(num_alloc_references);
+
+ /* add references from objects */
+ BoundBox bounds = BoundBox::empty, center = BoundBox::empty;
+ int i = 0;
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ ++i;
+ continue;
+ }
+ if (!ob->mesh->is_instanced())
+ add_reference_mesh(bounds, center, ob->mesh, i);
+ else
+ add_reference_object(bounds, center, ob, i);
+ }
+ else
+ add_reference_mesh(bounds, center, ob->mesh, i);
+
+ i++;
+
+ if (progress.get_cancel())
+ return;
+ }
+
+ /* happens mostly on empty meshes */
+ if (!bounds.valid())
+ bounds.grow(make_float3(0.0f, 0.0f, 0.0f));
+
+ root = BVHRange(bounds, center, 0, references.size());
}
/* Build */
-BVHNode* BVHBuild::run()
+BVHNode *BVHBuild::run()
{
- BVHRange root;
-
- /* add references */
- add_references(root);
-
- if(progress.get_cancel())
- return NULL;
-
- /* init spatial splits */
- if(params.top_level) {
- /* NOTE: Technically it is supported by the builder but it's not really
- * optimized for speed yet and not really clear yet if it has measurable
- * improvement on render time. Needs some extra investigation before
- * enabling spatial split for top level BVH.
- */
- params.use_spatial_split = false;
- }
-
- spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
- if(params.use_spatial_split) {
- /* NOTE: The API here tries to be as much ready for multi-threaded build
- * as possible, but at the same time it tries not to introduce any
- * changes in behavior for until all refactoring needed for threading is
- * finished.
- *
- * So we currently allocate single storage for now, which is only used by
- * the only thread working on the spatial BVH build.
- */
- spatial_storage.resize(TaskScheduler::num_threads() + 1);
- size_t num_bins = max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1;
- foreach(BVHSpatialStorage &storage, spatial_storage) {
- storage.right_bounds.clear();
- }
- spatial_storage[0].right_bounds.resize(num_bins);
- }
- spatial_free_index = 0;
-
- need_prim_time = params.num_motion_curve_steps > 0 ||
- params.num_motion_triangle_steps > 0;
-
- /* init progress updates */
- double build_start_time;
- build_start_time = progress_start_time = time_dt();
- progress_count = 0;
- progress_total = references.size();
- progress_original_total = progress_total;
-
- prim_type.resize(references.size());
- prim_index.resize(references.size());
- prim_object.resize(references.size());
- if(need_prim_time) {
- prim_time.resize(references.size());
- }
- else {
- prim_time.resize(0);
- }
-
- /* build recursively */
- BVHNode *rootnode;
-
- if(params.use_spatial_split) {
- /* Perform multithreaded spatial split build. */
- rootnode = build_node(root, &references, 0, 0);
- task_pool.wait_work();
- }
- else {
- /* Perform multithreaded binning build. */
- BVHObjectBinning rootbin(root, (references.size())? &references[0]: NULL);
- rootnode = build_node(rootbin, 0);
- task_pool.wait_work();
- }
-
- /* delete if we canceled */
- if(rootnode) {
- if(progress.get_cancel()) {
- rootnode->deleteSubtree();
- rootnode = NULL;
- VLOG(1) << "BVH build cancelled.";
- }
- else {
- /*rotate(rootnode, 4, 5);*/
- rootnode->update_visibility();
- rootnode->update_time();
- }
- if(rootnode != NULL) {
- VLOG(1) << "BVH build statistics:\n"
- << " Build time: " << time_dt() - build_start_time << "\n"
- << " Total number of nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT)) << "\n"
- << " Number of inner nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n"
- << " Number of leaf nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n"
- << " Number of unaligned nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT)) << "\n"
- << " Allocation slop factor: "
- << ((prim_type.capacity() != 0)
- ? (float)prim_type.size() / prim_type.capacity()
- : 1.0f) << "\n"
- << " Maximum depth: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
- }
- }
-
-
- return rootnode;
+ BVHRange root;
+
+ /* add references */
+ add_references(root);
+
+ if (progress.get_cancel())
+ return NULL;
+
+ /* init spatial splits */
+ if (params.top_level) {
+ /* NOTE: Technically it is supported by the builder but it's not really
+ * optimized for speed yet and not really clear yet if it has measurable
+ * improvement on render time. Needs some extra investigation before
+ * enabling spatial split for top level BVH.
+ */
+ params.use_spatial_split = false;
+ }
+
+ spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
+ if (params.use_spatial_split) {
+ /* NOTE: The API here tries to be as much ready for multi-threaded build
+ * as possible, but at the same time it tries not to introduce any
+ * changes in behavior for until all refactoring needed for threading is
+ * finished.
+ *
+ * So we currently allocate single storage for now, which is only used by
+ * the only thread working on the spatial BVH build.
+ */
+ spatial_storage.resize(TaskScheduler::num_threads() + 1);
+ size_t num_bins = max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1;
+ foreach (BVHSpatialStorage &storage, spatial_storage) {
+ storage.right_bounds.clear();
+ }
+ spatial_storage[0].right_bounds.resize(num_bins);
+ }
+ spatial_free_index = 0;
+
+ need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0;
+
+ /* init progress updates */
+ double build_start_time;
+ build_start_time = progress_start_time = time_dt();
+ progress_count = 0;
+ progress_total = references.size();
+ progress_original_total = progress_total;
+
+ prim_type.resize(references.size());
+ prim_index.resize(references.size());
+ prim_object.resize(references.size());
+ if (need_prim_time) {
+ prim_time.resize(references.size());
+ }
+ else {
+ prim_time.resize(0);
+ }
+
+ /* build recursively */
+ BVHNode *rootnode;
+
+ if (params.use_spatial_split) {
+ /* Perform multithreaded spatial split build. */
+ rootnode = build_node(root, &references, 0, 0);
+ task_pool.wait_work();
+ }
+ else {
+ /* Perform multithreaded binning build. */
+ BVHObjectBinning rootbin(root, (references.size()) ? &references[0] : NULL);
+ rootnode = build_node(rootbin, 0);
+ task_pool.wait_work();
+ }
+
+ /* delete if we canceled */
+ if (rootnode) {
+ if (progress.get_cancel()) {
+ rootnode->deleteSubtree();
+ rootnode = NULL;
+ VLOG(1) << "BVH build cancelled.";
+ }
+ else {
+ /*rotate(rootnode, 4, 5);*/
+ rootnode->update_visibility();
+ rootnode->update_time();
+ }
+ if (rootnode != NULL) {
+ VLOG(1) << "BVH build statistics:\n"
+ << " Build time: " << time_dt() - build_start_time << "\n"
+ << " Total number of nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
+ << "\n"
+ << " Number of inner nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
+ << "\n"
+ << " Number of leaf nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
+ << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
+ << "\n"
+ << " Allocation slop factor: "
+ << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
+ 1.0f)
+ << "\n"
+ << " Maximum depth: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
+ }
+ }
+
+ return rootnode;
}
void BVHBuild::progress_update()
{
- if(time_dt() - progress_start_time < 0.25)
- return;
+ if (time_dt() - progress_start_time < 0.25)
+ return;
- double progress_start = (double)progress_count/(double)progress_total;
- double duplicates = (double)(progress_total - progress_original_total)/(double)progress_total;
+ double progress_start = (double)progress_count / (double)progress_total;
+ double duplicates = (double)(progress_total - progress_original_total) / (double)progress_total;
- string msg = string_printf("Building BVH %.0f%%, duplicates %.0f%%",
- progress_start * 100.0, duplicates * 100.0);
+ string msg = string_printf(
+ "Building BVH %.0f%%, duplicates %.0f%%", progress_start * 100.0, duplicates * 100.0);
- progress.set_substatus(msg);
- progress_start_time = time_dt();
+ progress.set_substatus(msg);
+ progress_start_time = time_dt();
}
-void BVHBuild::thread_build_node(InnerNode *inner,
- int child,
- BVHObjectBinning *range,
- int level)
+void BVHBuild::thread_build_node(InnerNode *inner, int child, BVHObjectBinning *range, int level)
{
- if(progress.get_cancel())
- return;
+ if (progress.get_cancel())
+ return;
- /* build nodes */
- BVHNode *node = build_node(*range, level);
+ /* build nodes */
+ BVHNode *node = build_node(*range, level);
- /* set child in inner node */
- inner->children[child] = node;
+ /* set child in inner node */
+ inner->children[child] = node;
- /* update progress */
- if(range->size() < THREAD_TASK_SIZE) {
- /*rotate(node, INT_MAX, 5);*/
+ /* update progress */
+ if (range->size() < THREAD_TASK_SIZE) {
+ /*rotate(node, INT_MAX, 5);*/
- thread_scoped_lock lock(build_mutex);
+ thread_scoped_lock lock(build_mutex);
- progress_count += range->size();
- progress_update();
- }
+ progress_count += range->size();
+ progress_update();
+ }
}
void BVHBuild::thread_build_spatial_split_node(InnerNode *inner,
@@ -585,567 +551,528 @@ void BVHBuild::thread_build_spatial_split_node(InnerNode *inner,
int level,
int thread_id)
{
- if(progress.get_cancel()) {
- return;
- }
+ if (progress.get_cancel()) {
+ return;
+ }
- /* build nodes */
- BVHNode *node = build_node(*range, references, level, thread_id);
+ /* build nodes */
+ BVHNode *node = build_node(*range, references, level, thread_id);
- /* set child in inner node */
- inner->children[child] = node;
+ /* set child in inner node */
+ inner->children[child] = node;
}
-bool BVHBuild::range_within_max_leaf_size(const BVHRange& range,
- const vector<BVHReference>& references) const
+bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
+ const vector<BVHReference> &references) const
{
- size_t size = range.size();
- size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
-
- if(size > max_leaf_size)
- return false;
-
- size_t num_triangles = 0;
- size_t num_motion_triangles = 0;
- size_t num_curves = 0;
- size_t num_motion_curves = 0;
-
- for(int i = 0; i < size; i++) {
- const BVHReference& ref = references[range.start() + i];
-
- if(ref.prim_type() & PRIMITIVE_CURVE)
- num_curves++;
- if(ref.prim_type() & PRIMITIVE_MOTION_CURVE)
- num_motion_curves++;
- else if(ref.prim_type() & PRIMITIVE_TRIANGLE)
- num_triangles++;
- else if(ref.prim_type() & PRIMITIVE_MOTION_TRIANGLE)
- num_motion_triangles++;
- }
-
- return (num_triangles <= params.max_triangle_leaf_size) &&
- (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
- (num_curves <= params.max_curve_leaf_size) &&
- (num_motion_curves <= params.max_motion_curve_leaf_size);
+ size_t size = range.size();
+ size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
+
+ if (size > max_leaf_size)
+ return false;
+
+ size_t num_triangles = 0;
+ size_t num_motion_triangles = 0;
+ size_t num_curves = 0;
+ size_t num_motion_curves = 0;
+
+ for (int i = 0; i < size; i++) {
+ const BVHReference &ref = references[range.start() + i];
+
+ if (ref.prim_type() & PRIMITIVE_CURVE)
+ num_curves++;
+ if (ref.prim_type() & PRIMITIVE_MOTION_CURVE)
+ num_motion_curves++;
+ else if (ref.prim_type() & PRIMITIVE_TRIANGLE)
+ num_triangles++;
+ else if (ref.prim_type() & PRIMITIVE_MOTION_TRIANGLE)
+ num_motion_triangles++;
+ }
+
+ return (num_triangles <= params.max_triangle_leaf_size) &&
+ (num_motion_triangles <= params.max_motion_triangle_leaf_size) &&
+ (num_curves <= params.max_curve_leaf_size) &&
+ (num_motion_curves <= params.max_motion_curve_leaf_size);
}
/* multithreaded binning builder */
-BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
+BVHNode *BVHBuild::build_node(const BVHObjectBinning &range, int level)
{
- size_t size = range.size();
- float leafSAH = params.sah_primitive_cost * range.leafSAH;
- float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH;
-
- /* Have at least one inner node on top level, for performance and correct
- * visibility tests, since object instances do not check visibility flag.
- */
- if(!(range.size() > 0 && params.top_level && level == 0)) {
- /* Make leaf node when threshold reached or SAH tells us. */
- if((params.small_enough_for_leaf(size, level)) ||
- (range_within_max_leaf_size(range, references) && leafSAH < splitSAH))
- {
- return create_leaf_node(range, references);
- }
- }
-
- BVHObjectBinning unaligned_range;
- float unalignedSplitSAH = FLT_MAX;
- float unalignedLeafSAH = FLT_MAX;
- Transform aligned_space;
- bool do_unalinged_split = false;
- if(params.use_unaligned_nodes &&
- splitSAH > params.unaligned_split_threshold*leafSAH)
- {
- aligned_space = unaligned_heuristic.compute_aligned_space(
- range, &references[0]);
- unaligned_range = BVHObjectBinning(range,
- &references[0],
- &unaligned_heuristic,
- &aligned_space);
- unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
- params.sah_primitive_cost * unaligned_range.splitSAH;
- unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
- if(!(range.size() > 0 && params.top_level && level == 0)) {
- if(unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
- range_within_max_leaf_size(range, references))
- {
- return create_leaf_node(range, references);
- }
- }
- /* Check whether unaligned split is better than the regular one. */
- if(unalignedSplitSAH < splitSAH) {
- do_unalinged_split = true;
- }
- }
-
- /* Perform split. */
- BVHObjectBinning left, right;
- if(do_unalinged_split) {
- unaligned_range.split(&references[0], left, right);
- }
- else {
- range.split(&references[0], left, right);
- }
-
- BoundBox bounds;
- if(do_unalinged_split) {
- bounds = unaligned_heuristic.compute_aligned_boundbox(
- range, &references[0], aligned_space);
- }
- else {
- bounds = range.bounds();
- }
-
- /* Create inner node. */
- InnerNode *inner;
- if(range.size() < THREAD_TASK_SIZE) {
- /* local build */
- BVHNode *leftnode = build_node(left, level + 1);
- BVHNode *rightnode = build_node(right, level + 1);
-
- inner = new InnerNode(bounds, leftnode, rightnode);
- }
- else {
- /* Threaded build */
- inner = new InnerNode(bounds);
-
- task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true);
- task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true);
- }
-
- if(do_unalinged_split) {
- inner->set_aligned_space(aligned_space);
- }
-
- return inner;
+ size_t size = range.size();
+ float leafSAH = params.sah_primitive_cost * range.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * range.splitSAH;
+
+ /* Have at least one inner node on top level, for performance and correct
+ * visibility tests, since object instances do not check visibility flag.
+ */
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ /* Make leaf node when threshold reached or SAH tells us. */
+ if ((params.small_enough_for_leaf(size, level)) ||
+ (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) {
+ return create_leaf_node(range, references);
+ }
+ }
+
+ BVHObjectBinning unaligned_range;
+ float unalignedSplitSAH = FLT_MAX;
+ float unalignedLeafSAH = FLT_MAX;
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
+ aligned_space = unaligned_heuristic.compute_aligned_space(range, &references[0]);
+ unaligned_range = BVHObjectBinning(
+ range, &references[0], &unaligned_heuristic, &aligned_space);
+ unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
+ params.sah_primitive_cost * unaligned_range.splitSAH;
+ unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
+ range_within_max_leaf_size(range, references)) {
+ return create_leaf_node(range, references);
+ }
+ }
+ /* Check whether unaligned split is better than the regular one. */
+ if (unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
+
+ /* Perform split. */
+ BVHObjectBinning left, right;
+ if (do_unalinged_split) {
+ unaligned_range.split(&references[0], left, right);
+ }
+ else {
+ range.split(&references[0], left, right);
+ }
+
+ BoundBox bounds;
+ if (do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(range, &references[0], aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
+ /* Create inner node. */
+ InnerNode *inner;
+ if (range.size() < THREAD_TASK_SIZE) {
+ /* local build */
+ BVHNode *leftnode = build_node(left, level + 1);
+ BVHNode *rightnode = build_node(right, level + 1);
+
+ inner = new InnerNode(bounds, leftnode, rightnode);
+ }
+ else {
+ /* Threaded build */
+ inner = new InnerNode(bounds);
+
+ task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true);
+ task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true);
+ }
+
+ if (do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
+ return inner;
}
/* multithreaded spatial split builder */
-BVHNode* BVHBuild::build_node(const BVHRange& range,
+BVHNode *BVHBuild::build_node(const BVHRange &range,
vector<BVHReference> *references,
int level,
int thread_id)
{
- /* Update progress.
- *
- * TODO(sergey): Currently it matches old behavior, but we can move it to the
- * task thread (which will mimic non=split builder) and save some CPU ticks
- * on checking cancel status.
- */
- progress_update();
- if(progress.get_cancel()) {
- return NULL;
- }
-
- /* Small enough or too deep => create leaf. */
- if(!(range.size() > 0 && params.top_level && level == 0)) {
- if(params.small_enough_for_leaf(range.size(), level)) {
- progress_count += range.size();
- return create_leaf_node(range, *references);
- }
- }
-
- /* Perform splitting test. */
- BVHSpatialStorage *storage = &spatial_storage[thread_id];
- BVHMixedSplit split(this, storage, range, references, level);
-
- if(!(range.size() > 0 && params.top_level && level == 0)) {
- if(split.no_split) {
- progress_count += range.size();
- return create_leaf_node(range, *references);
- }
- }
- float leafSAH = params.sah_primitive_cost * split.leafSAH;
- float splitSAH = params.sah_node_cost * range.bounds().half_area() +
- params.sah_primitive_cost * split.nodeSAH;
-
- BVHMixedSplit unaligned_split;
- float unalignedSplitSAH = FLT_MAX;
- /* float unalignedLeafSAH = FLT_MAX; */
- Transform aligned_space;
- bool do_unalinged_split = false;
- if(params.use_unaligned_nodes &&
- splitSAH > params.unaligned_split_threshold*leafSAH)
- {
- aligned_space =
- unaligned_heuristic.compute_aligned_space(range, &references->at(0));
- unaligned_split = BVHMixedSplit(this,
- storage,
- range,
- references,
- level,
- &unaligned_heuristic,
- &aligned_space);
- /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
- unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
- params.sah_primitive_cost * unaligned_split.nodeSAH;
- /* TOOD(sergey): Check we can create leaf already. */
- /* Check whether unaligned split is better than the regulat one. */
- if(unalignedSplitSAH < splitSAH) {
- do_unalinged_split = true;
- }
- }
-
- /* Do split. */
- BVHRange left, right;
- if(do_unalinged_split) {
- unaligned_split.split(this, left, right, range);
- }
- else {
- split.split(this, left, right, range);
- }
-
- progress_total += left.size() + right.size() - range.size();
-
- BoundBox bounds;
- if(do_unalinged_split) {
- bounds = unaligned_heuristic.compute_aligned_boundbox(
- range, &references->at(0), aligned_space);
- }
- else {
- bounds = range.bounds();
- }
-
- /* Create inner node. */
- InnerNode *inner;
- if(range.size() < THREAD_TASK_SIZE) {
- /* Local build. */
-
- /* Build left node. */
- vector<BVHReference> copy(references->begin() + right.start(),
- references->begin() + right.end());
- right.set_start(0);
-
- BVHNode *leftnode = build_node(left, references, level + 1, thread_id);
-
- /* Build right node. */
- BVHNode *rightnode = build_node(right, &copy, level + 1, thread_id);
-
- inner = new InnerNode(bounds, leftnode, rightnode);
- }
- else {
- /* Threaded build. */
- inner = new InnerNode(bounds);
- task_pool.push(new BVHSpatialSplitBuildTask(this,
- inner,
- 0,
- left,
- *references,
- level + 1),
- true);
- task_pool.push(new BVHSpatialSplitBuildTask(this,
- inner,
- 1,
- right,
- *references,
- level + 1),
- true);
- }
-
- if(do_unalinged_split) {
- inner->set_aligned_space(aligned_space);
- }
-
- return inner;
+ /* Update progress.
+ *
+ * TODO(sergey): Currently it matches old behavior, but we can move it to the
+ * task thread (which will mimic non=split builder) and save some CPU ticks
+ * on checking cancel status.
+ */
+ progress_update();
+ if (progress.get_cancel()) {
+ return NULL;
+ }
+
+ /* Small enough or too deep => create leaf. */
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (params.small_enough_for_leaf(range.size(), level)) {
+ progress_count += range.size();
+ return create_leaf_node(range, *references);
+ }
+ }
+
+ /* Perform splitting test. */
+ BVHSpatialStorage *storage = &spatial_storage[thread_id];
+ BVHMixedSplit split(this, storage, range, references, level);
+
+ if (!(range.size() > 0 && params.top_level && level == 0)) {
+ if (split.no_split) {
+ progress_count += range.size();
+ return create_leaf_node(range, *references);
+ }
+ }
+ float leafSAH = params.sah_primitive_cost * split.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * split.nodeSAH;
+
+ BVHMixedSplit unaligned_split;
+ float unalignedSplitSAH = FLT_MAX;
+ /* float unalignedLeafSAH = FLT_MAX; */
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if (params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold * leafSAH) {
+ aligned_space = unaligned_heuristic.compute_aligned_space(range, &references->at(0));
+ unaligned_split = BVHMixedSplit(
+ this, storage, range, references, level, &unaligned_heuristic, &aligned_space);
+ /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
+ unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
+ params.sah_primitive_cost * unaligned_split.nodeSAH;
+ /* TOOD(sergey): Check we can create leaf already. */
+ /* Check whether unaligned split is better than the regulat one. */
+ if (unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
+
+ /* Do split. */
+ BVHRange left, right;
+ if (do_unalinged_split) {
+ unaligned_split.split(this, left, right, range);
+ }
+ else {
+ split.split(this, left, right, range);
+ }
+
+ progress_total += left.size() + right.size() - range.size();
+
+ BoundBox bounds;
+ if (do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(
+ range, &references->at(0), aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
+ /* Create inner node. */
+ InnerNode *inner;
+ if (range.size() < THREAD_TASK_SIZE) {
+ /* Local build. */
+
+ /* Build left node. */
+ vector<BVHReference> copy(references->begin() + right.start(),
+ references->begin() + right.end());
+ right.set_start(0);
+
+ BVHNode *leftnode = build_node(left, references, level + 1, thread_id);
+
+ /* Build right node. */
+ BVHNode *rightnode = build_node(right, &copy, level + 1, thread_id);
+
+ inner = new InnerNode(bounds, leftnode, rightnode);
+ }
+ else {
+ /* Threaded build. */
+ inner = new InnerNode(bounds);
+ task_pool.push(new BVHSpatialSplitBuildTask(this, inner, 0, left, *references, level + 1),
+ true);
+ task_pool.push(new BVHSpatialSplitBuildTask(this, inner, 1, right, *references, level + 1),
+ true);
+ }
+
+ if (do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
+ return inner;
}
/* Create Nodes */
BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, int num)
{
- if(num == 0) {
- BoundBox bounds = BoundBox::empty;
- return new LeafNode(bounds, 0, 0, 0);
- }
- else if(num == 1) {
- assert(start < prim_type.size());
- prim_type[start] = ref->prim_type();
- prim_index[start] = ref->prim_index();
- prim_object[start] = ref->prim_object();
- if(need_prim_time) {
- prim_time[start] = make_float2(ref->time_from(), ref->time_to());
- }
-
- const uint visibility = objects[ref->prim_object()]->visibility_for_tracing();
- BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1);
- leaf_node->time_from = ref->time_from();
- leaf_node->time_to = ref->time_to();
- return leaf_node;
- }
- else {
- int mid = num/2;
- BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
- BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid);
-
- BoundBox bounds = BoundBox::empty;
- bounds.grow(leaf0->bounds);
- bounds.grow(leaf1->bounds);
-
- BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
- inner_node->time_from = min(leaf0->time_from, leaf1->time_from);
- inner_node->time_to = max(leaf0->time_to, leaf1->time_to);
- return inner_node;
- }
+ if (num == 0) {
+ BoundBox bounds = BoundBox::empty;
+ return new LeafNode(bounds, 0, 0, 0);
+ }
+ else if (num == 1) {
+ assert(start < prim_type.size());
+ prim_type[start] = ref->prim_type();
+ prim_index[start] = ref->prim_index();
+ prim_object[start] = ref->prim_object();
+ if (need_prim_time) {
+ prim_time[start] = make_float2(ref->time_from(), ref->time_to());
+ }
+
+ const uint visibility = objects[ref->prim_object()]->visibility_for_tracing();
+ BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start + 1);
+ leaf_node->time_from = ref->time_from();
+ leaf_node->time_to = ref->time_to();
+ return leaf_node;
+ }
+ else {
+ int mid = num / 2;
+ BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid);
+ BVHNode *leaf1 = create_object_leaf_nodes(ref + mid, start + mid, num - mid);
+
+ BoundBox bounds = BoundBox::empty;
+ bounds.grow(leaf0->bounds);
+ bounds.grow(leaf1->bounds);
+
+ BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1);
+ inner_node->time_from = min(leaf0->time_from, leaf1->time_from);
+ inner_node->time_to = max(leaf0->time_to, leaf1->time_to);
+ return inner_node;
+ }
}
-BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
- const vector<BVHReference>& references)
+BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHReference> &references)
{
- /* This is a bit overallocating here (considering leaf size into account),
- * but chunk-based re-allocation in vector makes it difficult to use small
- * size of stack storage here. Some tweaks are possible tho.
- *
- * NOTES:
- * - If the size is too big, we'll have inefficient stack usage,
- * and lots of cache misses.
- * - If the size is too small, then we can run out of memory
- * allowed to be used by vector.
- * In practice it wouldn't mean crash, just allocator will fallback
- * to heap which is slower.
- * - Optimistic re-allocation in STL could jump us out of stack usage
- * because re-allocation happens in chunks and size of those chunks we
- * can not control.
- */
- typedef StackAllocator<256, int> LeafStackAllocator;
- typedef StackAllocator<256, float2> LeafTimeStackAllocator;
- typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
-
- vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
- vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
- vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
- vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM_TOTAL];
- vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
-
- /* TODO(sergey): In theory we should be able to store references. */
- vector<BVHReference, LeafReferenceStackAllocator> object_references;
-
- uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
- /* NOTE: Keep initializtion in sync with actual number of primitives. */
- BoundBox bounds[PRIMITIVE_NUM_TOTAL] = {BoundBox::empty,
- BoundBox::empty,
- BoundBox::empty,
- BoundBox::empty};
- int ob_num = 0;
- int num_new_prims = 0;
- /* Fill in per-type type/index array. */
- for(int i = 0; i < range.size(); i++) {
- const BVHReference& ref = references[range.start() + i];
- if(ref.prim_index() != -1) {
- int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL);
- p_ref[type_index].push_back(ref);
- p_type[type_index].push_back(ref.prim_type());
- p_index[type_index].push_back(ref.prim_index());
- p_object[type_index].push_back(ref.prim_object());
- p_time[type_index].push_back(make_float2(ref.time_from(),
- ref.time_to()));
-
- bounds[type_index].grow(ref.bounds());
- visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing();
- if(ref.prim_type() & PRIMITIVE_ALL_CURVE) {
- visibility[type_index] |= PATH_RAY_CURVE;
- }
- ++num_new_prims;
- }
- else {
- object_references.push_back(ref);
- ++ob_num;
- }
- }
-
- /* Create leaf nodes for every existing primitive.
- *
- * Here we write primitive types, indices and objects to a temporary array.
- * This way we keep all the heavy memory allocation code outside of the
- * thread lock in the case of spatial split building.
- *
- * TODO(sergey): With some pointer trickery we can write directly to the
- * destination buffers for the non-spatial split BVH.
- */
- BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
- int num_leaves = 0;
- size_t start_index = 0;
- vector<int, LeafStackAllocator> local_prim_type,
- local_prim_index,
- local_prim_object;
- vector<float2, LeafTimeStackAllocator> local_prim_time;
- local_prim_type.resize(num_new_prims);
- local_prim_index.resize(num_new_prims);
- local_prim_object.resize(num_new_prims);
- if(need_prim_time) {
- local_prim_time.resize(num_new_prims);
- }
- for(int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
- int num = (int)p_type[i].size();
- if(num != 0) {
- assert(p_type[i].size() == p_index[i].size());
- assert(p_type[i].size() == p_object[i].size());
- Transform aligned_space;
- bool alignment_found = false;
- for(int j = 0; j < num; ++j) {
- const int index = start_index + j;
- local_prim_type[index] = p_type[i][j];
- local_prim_index[index] = p_index[i][j];
- local_prim_object[index] = p_object[i][j];
- if(need_prim_time) {
- local_prim_time[index] = p_time[i][j];
- }
- if(params.use_unaligned_nodes && !alignment_found) {
- alignment_found =
- unaligned_heuristic.compute_aligned_space(p_ref[i][j],
- &aligned_space);
- }
- }
- LeafNode *leaf_node = new LeafNode(bounds[i],
- visibility[i],
- start_index,
- start_index + num);
- if(true) {
- float time_from = 1.0f, time_to = 0.0f;
- for(int j = 0; j < num; ++j) {
- const BVHReference &ref = p_ref[i][j];
- time_from = min(time_from, ref.time_from());
- time_to = max(time_to, ref.time_to());
- }
- leaf_node->time_from = time_from;
- leaf_node->time_to = time_to;
- }
- if(alignment_found) {
- /* Need to recalculate leaf bounds with new alignment. */
- leaf_node->bounds = BoundBox::empty;
- for(int j = 0; j < num; ++j) {
- const BVHReference &ref = p_ref[i][j];
- BoundBox ref_bounds =
- unaligned_heuristic.compute_aligned_prim_boundbox(
- ref,
- aligned_space);
- leaf_node->bounds.grow(ref_bounds);
- }
- /* Set alignment space. */
- leaf_node->set_aligned_space(aligned_space);
- }
- leaves[num_leaves++] = leaf_node;
- start_index += num;
- }
- }
- /* Get size of new data to be copied to the packed arrays. */
- const int num_new_leaf_data = start_index;
- const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
- /* Copy actual data to the packed array. */
- if(params.use_spatial_split) {
- spatial_spin_lock.lock();
- /* We use first free index in the packed arrays and mode pointer to the
- * end of the current range.
- *
- * This doesn't give deterministic packed arrays, but it shouldn't really
- * matter because order of children in BVH is deterministic.
- */
- start_index = spatial_free_index;
- spatial_free_index += range.size();
- /* Extend an array when needed. */
- const size_t range_end = start_index + range.size();
- if(prim_type.size() < range_end) {
- /* Avoid extra re-allocations by pre-allocating bigger array in an
- * advance.
- */
- if(range_end >= prim_type.capacity()) {
- float progress = (float)progress_count/(float)progress_total;
- float factor = (1.0f - progress);
- const size_t reserve = (size_t)(range_end + (float)range_end*factor);
- prim_type.reserve(reserve);
- prim_index.reserve(reserve);
- prim_object.reserve(reserve);
- if(need_prim_time) {
- prim_time.reserve(reserve);
- }
- }
-
- prim_type.resize(range_end);
- prim_index.resize(range_end);
- prim_object.resize(range_end);
- if(need_prim_time) {
- prim_time.resize(range_end);
- }
- }
- /* Perform actual data copy. */
- if(new_leaf_data_size > 0) {
- memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
- memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
- memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
- if(need_prim_time) {
- memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2)*num_new_leaf_data);
- }
- }
- spatial_spin_lock.unlock();
- }
- else {
- /* For the regular BVH builder we simply copy new data starting at the
- * range start. This is totally thread-safe, all threads are living
- * inside of their own range.
- */
- start_index = range.start();
- if(new_leaf_data_size > 0) {
- memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
- memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
- memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
- if(need_prim_time) {
- memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2)*num_new_leaf_data);
- }
- }
- }
-
- /* So far leaves were created with the zero-based index in an arrays,
- * here we modify the indices to correspond to actual packed array start
- * index.
- */
- for(int i = 0; i < num_leaves; ++i) {
- LeafNode *leaf = (LeafNode *)leaves[i];
- leaf->lo += start_index;
- leaf->hi += start_index;
- }
-
- /* Create leaf node for object. */
- if(num_leaves == 0 || ob_num) {
- /* Only create object leaf nodes if there are objects or no other
- * nodes created.
- */
- const BVHReference *ref = (ob_num)? &object_references[0]: NULL;
- leaves[num_leaves] = create_object_leaf_nodes(ref,
- start_index + num_new_leaf_data,
- ob_num);
- ++num_leaves;
- }
-
- /* TODO(sergey): Need to take care of alignment when number of leaves
- * is more than 1.
- */
- if(num_leaves == 1) {
- /* Simplest case: single leaf, just return it.
- * In all the rest cases we'll be creating intermediate inner node with
- * an appropriate bounding box.
- */
- return leaves[0];
- }
- else if(num_leaves == 2) {
- return new InnerNode(range.bounds(), leaves[0], leaves[1]);
- }
- else if(num_leaves == 3) {
- BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds);
- BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
- return new InnerNode(range.bounds(), leaves[0], inner);
- } else {
- /* Should be doing more branches if more primitive types added. */
- assert(num_leaves <= 5);
- BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds);
- BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds);
- BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
- BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
- BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds);
- BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
- if(num_leaves == 5) {
- return new InnerNode(range.bounds(), inner_c, leaves[4]);
- }
- return inner_c;
- }
+ /* This is a bit overallocating here (considering leaf size into account),
+ * but chunk-based re-allocation in vector makes it difficult to use small
+ * size of stack storage here. Some tweaks are possible tho.
+ *
+ * NOTES:
+ * - If the size is too big, we'll have inefficient stack usage,
+ * and lots of cache misses.
+ * - If the size is too small, then we can run out of memory
+ * allowed to be used by vector.
+ * In practice it wouldn't mean crash, just allocator will fallback
+ * to heap which is slower.
+ * - Optimistic re-allocation in STL could jump us out of stack usage
+ * because re-allocation happens in chunks and size of those chunks we
+ * can not control.
+ */
+ typedef StackAllocator<256, int> LeafStackAllocator;
+ typedef StackAllocator<256, float2> LeafTimeStackAllocator;
+ typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
+
+ vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
+ vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
+ vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
+ vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM_TOTAL];
+ vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
+
+ /* TODO(sergey): In theory we should be able to store references. */
+ vector<BVHReference, LeafReferenceStackAllocator> object_references;
+
+ uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
+ /* NOTE: Keep initializtion in sync with actual number of primitives. */
+ BoundBox bounds[PRIMITIVE_NUM_TOTAL] = {
+ BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
+ int ob_num = 0;
+ int num_new_prims = 0;
+ /* Fill in per-type type/index array. */
+ for (int i = 0; i < range.size(); i++) {
+ const BVHReference &ref = references[range.start() + i];
+ if (ref.prim_index() != -1) {
+ int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL);
+ p_ref[type_index].push_back(ref);
+ p_type[type_index].push_back(ref.prim_type());
+ p_index[type_index].push_back(ref.prim_index());
+ p_object[type_index].push_back(ref.prim_object());
+ p_time[type_index].push_back(make_float2(ref.time_from(), ref.time_to()));
+
+ bounds[type_index].grow(ref.bounds());
+ visibility[type_index] |= objects[ref.prim_object()]->visibility_for_tracing();
+ if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ visibility[type_index] |= PATH_RAY_CURVE;
+ }
+ ++num_new_prims;
+ }
+ else {
+ object_references.push_back(ref);
+ ++ob_num;
+ }
+ }
+
+ /* Create leaf nodes for every existing primitive.
+ *
+ * Here we write primitive types, indices and objects to a temporary array.
+ * This way we keep all the heavy memory allocation code outside of the
+ * thread lock in the case of spatial split building.
+ *
+ * TODO(sergey): With some pointer trickery we can write directly to the
+ * destination buffers for the non-spatial split BVH.
+ */
+ BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
+ int num_leaves = 0;
+ size_t start_index = 0;
+ vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
+ vector<float2, LeafTimeStackAllocator> local_prim_time;
+ local_prim_type.resize(num_new_prims);
+ local_prim_index.resize(num_new_prims);
+ local_prim_object.resize(num_new_prims);
+ if (need_prim_time) {
+ local_prim_time.resize(num_new_prims);
+ }
+ for (int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
+ int num = (int)p_type[i].size();
+ if (num != 0) {
+ assert(p_type[i].size() == p_index[i].size());
+ assert(p_type[i].size() == p_object[i].size());
+ Transform aligned_space;
+ bool alignment_found = false;
+ for (int j = 0; j < num; ++j) {
+ const int index = start_index + j;
+ local_prim_type[index] = p_type[i][j];
+ local_prim_index[index] = p_index[i][j];
+ local_prim_object[index] = p_object[i][j];
+ if (need_prim_time) {
+ local_prim_time[index] = p_time[i][j];
+ }
+ if (params.use_unaligned_nodes && !alignment_found) {
+ alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], &aligned_space);
+ }
+ }
+ LeafNode *leaf_node = new LeafNode(bounds[i], visibility[i], start_index, start_index + num);
+ if (true) {
+ float time_from = 1.0f, time_to = 0.0f;
+ for (int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ time_from = min(time_from, ref.time_from());
+ time_to = max(time_to, ref.time_to());
+ }
+ leaf_node->time_from = time_from;
+ leaf_node->time_to = time_to;
+ }
+ if (alignment_found) {
+ /* Need to recalculate leaf bounds with new alignment. */
+ leaf_node->bounds = BoundBox::empty;
+ for (int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ BoundBox ref_bounds = unaligned_heuristic.compute_aligned_prim_boundbox(ref,
+ aligned_space);
+ leaf_node->bounds.grow(ref_bounds);
+ }
+ /* Set alignment space. */
+ leaf_node->set_aligned_space(aligned_space);
+ }
+ leaves[num_leaves++] = leaf_node;
+ start_index += num;
+ }
+ }
+ /* Get size of new data to be copied to the packed arrays. */
+ const int num_new_leaf_data = start_index;
+ const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
+ /* Copy actual data to the packed array. */
+ if (params.use_spatial_split) {
+ spatial_spin_lock.lock();
+ /* We use first free index in the packed arrays and mode pointer to the
+ * end of the current range.
+ *
+ * This doesn't give deterministic packed arrays, but it shouldn't really
+ * matter because order of children in BVH is deterministic.
+ */
+ start_index = spatial_free_index;
+ spatial_free_index += range.size();
+ /* Extend an array when needed. */
+ const size_t range_end = start_index + range.size();
+ if (prim_type.size() < range_end) {
+ /* Avoid extra re-allocations by pre-allocating bigger array in an
+ * advance.
+ */
+ if (range_end >= prim_type.capacity()) {
+ float progress = (float)progress_count / (float)progress_total;
+ float factor = (1.0f - progress);
+ const size_t reserve = (size_t)(range_end + (float)range_end * factor);
+ prim_type.reserve(reserve);
+ prim_index.reserve(reserve);
+ prim_object.reserve(reserve);
+ if (need_prim_time) {
+ prim_time.reserve(reserve);
+ }
+ }
+
+ prim_type.resize(range_end);
+ prim_index.resize(range_end);
+ prim_object.resize(range_end);
+ if (need_prim_time) {
+ prim_time.resize(range_end);
+ }
+ }
+ /* Perform actual data copy. */
+ if (new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
+ if (need_prim_time) {
+ memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
+ }
+ }
+ spatial_spin_lock.unlock();
+ }
+ else {
+ /* For the regular BVH builder we simply copy new data starting at the
+ * range start. This is totally thread-safe, all threads are living
+ * inside of their own range.
+ */
+ start_index = range.start();
+ if (new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
+ if (need_prim_time) {
+ memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2) * num_new_leaf_data);
+ }
+ }
+ }
+
+ /* So far leaves were created with the zero-based index in an arrays,
+ * here we modify the indices to correspond to actual packed array start
+ * index.
+ */
+ for (int i = 0; i < num_leaves; ++i) {
+ LeafNode *leaf = (LeafNode *)leaves[i];
+ leaf->lo += start_index;
+ leaf->hi += start_index;
+ }
+
+ /* Create leaf node for object. */
+ if (num_leaves == 0 || ob_num) {
+ /* Only create object leaf nodes if there are objects or no other
+ * nodes created.
+ */
+ const BVHReference *ref = (ob_num) ? &object_references[0] : NULL;
+ leaves[num_leaves] = create_object_leaf_nodes(ref, start_index + num_new_leaf_data, ob_num);
+ ++num_leaves;
+ }
+
+ /* TODO(sergey): Need to take care of alignment when number of leaves
+ * is more than 1.
+ */
+ if (num_leaves == 1) {
+ /* Simplest case: single leaf, just return it.
+ * In all the rest cases we'll be creating intermediate inner node with
+ * an appropriate bounding box.
+ */
+ return leaves[0];
+ }
+ else if (num_leaves == 2) {
+ return new InnerNode(range.bounds(), leaves[0], leaves[1]);
+ }
+ else if (num_leaves == 3) {
+ BoundBox inner_bounds = merge(leaves[1]->bounds, leaves[2]->bounds);
+ BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
+ return new InnerNode(range.bounds(), leaves[0], inner);
+ }
+ else {
+ /* Should be doing more branches if more primitive types added. */
+ assert(num_leaves <= 5);
+ BoundBox inner_bounds_a = merge(leaves[0]->bounds, leaves[1]->bounds);
+ BoundBox inner_bounds_b = merge(leaves[2]->bounds, leaves[3]->bounds);
+ BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
+ BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
+ BoundBox inner_bounds_c = merge(inner_a->bounds, inner_b->bounds);
+ BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
+ if (num_leaves == 5) {
+ return new InnerNode(range.bounds(), inner_c, leaves[4]);
+ }
+ return inner_c;
+ }
#undef MAX_ITEMS_PER_LEAF
}
@@ -1154,81 +1081,81 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
void BVHBuild::rotate(BVHNode *node, int max_depth, int iterations)
{
- /* in tested scenes, this resulted in slightly slower raytracing, so disabled
- * it for now. could be implementation bug, or depend on the scene */
- if(node)
- for(int i = 0; i < iterations; i++)
- rotate(node, max_depth);
+ /* in tested scenes, this resulted in slightly slower raytracing, so disabled
+ * it for now. could be implementation bug, or depend on the scene */
+ if (node)
+ for (int i = 0; i < iterations; i++)
+ rotate(node, max_depth);
}
void BVHBuild::rotate(BVHNode *node, int max_depth)
{
- /* nothing to rotate if we reached a leaf node. */
- if(node->is_leaf() || max_depth < 0)
- return;
-
- InnerNode *parent = (InnerNode*)node;
-
- /* rotate all children first */
- for(size_t c = 0; c < 2; c++)
- rotate(parent->children[c], max_depth-1);
-
- /* compute current area of all children */
- BoundBox bounds0 = parent->children[0]->bounds;
- BoundBox bounds1 = parent->children[1]->bounds;
-
- float area0 = bounds0.half_area();
- float area1 = bounds1.half_area();
- float4 child_area = make_float4(area0, area1, 0.0f, 0.0f);
-
- /* find best rotation. we pick a target child of a first child, and swap
- * this with an other child. we perform the best such swap. */
- float best_cost = FLT_MAX;
- int best_child = -1, best_target = -1, best_other = -1;
-
- for(size_t c = 0; c < 2; c++) {
- /* ignore leaf nodes as we cannot descent into */
- if(parent->children[c]->is_leaf())
- continue;
-
- InnerNode *child = (InnerNode*)parent->children[c];
- BoundBox& other = (c == 0)? bounds1: bounds0;
-
- /* transpose child bounds */
- BoundBox target0 = child->children[0]->bounds;
- BoundBox target1 = child->children[1]->bounds;
-
- /* compute cost for both possible swaps */
- float cost0 = merge(other, target1).half_area() - child_area[c];
- float cost1 = merge(target0, other).half_area() - child_area[c];
-
- if(min(cost0,cost1) < best_cost) {
- best_child = (int)c;
- best_other = (int)(1-c);
-
- if(cost0 < cost1) {
- best_cost = cost0;
- best_target = 0;
- }
- else {
- best_cost = cost0;
- best_target = 1;
- }
- }
- }
-
- /* if we did not find a swap that improves the SAH then do nothing */
- if(best_cost >= 0)
- return;
-
- assert(best_child == 0 || best_child == 1);
- assert(best_target != -1);
-
- /* perform the best found tree rotation */
- InnerNode *child = (InnerNode*)parent->children[best_child];
-
- swap(parent->children[best_other], child->children[best_target]);
- child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds);
+ /* nothing to rotate if we reached a leaf node. */
+ if (node->is_leaf() || max_depth < 0)
+ return;
+
+ InnerNode *parent = (InnerNode *)node;
+
+ /* rotate all children first */
+ for (size_t c = 0; c < 2; c++)
+ rotate(parent->children[c], max_depth - 1);
+
+ /* compute current area of all children */
+ BoundBox bounds0 = parent->children[0]->bounds;
+ BoundBox bounds1 = parent->children[1]->bounds;
+
+ float area0 = bounds0.half_area();
+ float area1 = bounds1.half_area();
+ float4 child_area = make_float4(area0, area1, 0.0f, 0.0f);
+
+ /* find best rotation. we pick a target child of a first child, and swap
+ * this with an other child. we perform the best such swap. */
+ float best_cost = FLT_MAX;
+ int best_child = -1, best_target = -1, best_other = -1;
+
+ for (size_t c = 0; c < 2; c++) {
+ /* ignore leaf nodes as we cannot descent into */
+ if (parent->children[c]->is_leaf())
+ continue;
+
+ InnerNode *child = (InnerNode *)parent->children[c];
+ BoundBox &other = (c == 0) ? bounds1 : bounds0;
+
+ /* transpose child bounds */
+ BoundBox target0 = child->children[0]->bounds;
+ BoundBox target1 = child->children[1]->bounds;
+
+ /* compute cost for both possible swaps */
+ float cost0 = merge(other, target1).half_area() - child_area[c];
+ float cost1 = merge(target0, other).half_area() - child_area[c];
+
+ if (min(cost0, cost1) < best_cost) {
+ best_child = (int)c;
+ best_other = (int)(1 - c);
+
+ if (cost0 < cost1) {
+ best_cost = cost0;
+ best_target = 0;
+ }
+ else {
+ best_cost = cost0;
+ best_target = 1;
+ }
+ }
+ }
+
+ /* if we did not find a swap that improves the SAH then do nothing */
+ if (best_cost >= 0)
+ return;
+
+ assert(best_child == 0 || best_child == 1);
+ assert(best_target != -1);
+
+ /* perform the best found tree rotation */
+ InnerNode *child = (InnerNode *)parent->children[best_child];
+
+ swap(parent->children[best_other], child->children[best_target]);
+ child->bounds = merge(child->children[0]->bounds, child->children[1]->bounds);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index dd95a5cc0e8..9685e26cfac 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -41,106 +41,101 @@ class Progress;
/* BVH Builder */
-class BVHBuild
-{
-public:
- /* Constructor/Destructor */
- 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);
- ~BVHBuild();
-
- BVHNode *run();
-
-protected:
- friend class BVHMixedSplit;
- friend class BVHObjectSplit;
- friend class BVHSpatialSplit;
- friend class BVHBuildTask;
- friend class BVHSpatialSplitBuildTask;
- friend class BVHObjectBinning;
-
- /* Adding references. */
- void add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
- void add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
- void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
- void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i);
- void add_references(BVHRange& root);
-
- /* Building. */
- BVHNode *build_node(const BVHRange& range,
- vector<BVHReference> *references,
- int level,
- int thread_id);
- BVHNode *build_node(const BVHObjectBinning& range, int level);
- BVHNode *create_leaf_node(const BVHRange& range,
- const vector<BVHReference>& references);
- BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
-
- bool range_within_max_leaf_size(const BVHRange& range,
- const vector<BVHReference>& references) const;
-
- /* Threads. */
- enum { THREAD_TASK_SIZE = 4096 };
- void thread_build_node(InnerNode *node,
- int child,
- BVHObjectBinning *range,
- int level);
- void thread_build_spatial_split_node(InnerNode *node,
- int child,
- BVHRange *range,
- vector<BVHReference> *references,
- int level,
- int thread_id);
- thread_mutex build_mutex;
-
- /* Progress. */
- void progress_update();
-
- /* Tree rotations. */
- void rotate(BVHNode *node, int max_depth);
- void rotate(BVHNode *node, int max_depth, int iterations);
-
- /* Objects and primitive references. */
- vector<Object*> objects;
- vector<BVHReference> references;
- int num_original_references;
-
- /* Output primitive indexes and objects. */
- array<int>& prim_type;
- array<int>& prim_index;
- array<int>& prim_object;
- array<float2>& prim_time;
-
- bool need_prim_time;
-
- /* Build parameters. */
- BVHParams params;
-
- /* Progress reporting. */
- Progress& progress;
- double progress_start_time;
- size_t progress_count;
- size_t progress_total;
- size_t progress_original_total;
-
- /* Spatial splitting. */
- float spatial_min_overlap;
- vector<BVHSpatialStorage> spatial_storage;
- size_t spatial_free_index;
- thread_spin_lock spatial_spin_lock;
-
- /* Threads. */
- TaskPool task_pool;
-
- /* Unaligned building. */
- BVHUnaligned unaligned_heuristic;
+class BVHBuild {
+ public:
+ /* Constructor/Destructor */
+ 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);
+ ~BVHBuild();
+
+ BVHNode *run();
+
+ protected:
+ friend class BVHMixedSplit;
+ friend class BVHObjectSplit;
+ friend class BVHSpatialSplit;
+ friend class BVHBuildTask;
+ friend class BVHSpatialSplitBuildTask;
+ friend class BVHObjectBinning;
+
+ /* Adding references. */
+ void add_reference_triangles(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
+ void add_reference_curves(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
+ void add_reference_mesh(BoundBox &root, BoundBox &center, Mesh *mesh, int i);
+ void add_reference_object(BoundBox &root, BoundBox &center, Object *ob, int i);
+ void add_references(BVHRange &root);
+
+ /* Building. */
+ BVHNode *build_node(const BVHRange &range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id);
+ BVHNode *build_node(const BVHObjectBinning &range, int level);
+ BVHNode *create_leaf_node(const BVHRange &range, const vector<BVHReference> &references);
+ BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
+
+ bool range_within_max_leaf_size(const BVHRange &range,
+ const vector<BVHReference> &references) const;
+
+ /* Threads. */
+ enum { THREAD_TASK_SIZE = 4096 };
+ void thread_build_node(InnerNode *node, int child, BVHObjectBinning *range, int level);
+ void thread_build_spatial_split_node(InnerNode *node,
+ int child,
+ BVHRange *range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id);
+ thread_mutex build_mutex;
+
+ /* Progress. */
+ void progress_update();
+
+ /* Tree rotations. */
+ void rotate(BVHNode *node, int max_depth);
+ void rotate(BVHNode *node, int max_depth, int iterations);
+
+ /* Objects and primitive references. */
+ vector<Object *> objects;
+ vector<BVHReference> references;
+ int num_original_references;
+
+ /* Output primitive indexes and objects. */
+ array<int> &prim_type;
+ array<int> &prim_index;
+ array<int> &prim_object;
+ array<float2> &prim_time;
+
+ bool need_prim_time;
+
+ /* Build parameters. */
+ BVHParams params;
+
+ /* Progress reporting. */
+ Progress &progress;
+ double progress_start_time;
+ size_t progress_count;
+ size_t progress_total;
+ size_t progress_original_total;
+
+ /* Spatial splitting. */
+ float spatial_min_overlap;
+ vector<BVHSpatialStorage> spatial_storage;
+ size_t spatial_free_index;
+ thread_spin_lock spatial_spin_lock;
+
+ /* Threads. */
+ TaskPool task_pool;
+
+ /* Unaligned building. */
+ BVHUnaligned unaligned_heuristic;
};
CCL_NAMESPACE_END
-#endif /* __BVH_BUILD_H__ */
+#endif /* __BVH_BUILD_H__ */
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp
index fa9993d8ac3..5ef9622aba2 100644
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ b/intern/cycles/bvh/bvh_embree.cpp
@@ -34,28 +34,28 @@
#ifdef WITH_EMBREE
-#include <pmmintrin.h>
-#include <xmmintrin.h>
-#include <embree3/rtcore_geometry.h>
+# include <pmmintrin.h>
+# include <xmmintrin.h>
+# include <embree3/rtcore_geometry.h>
-#include "bvh/bvh_embree.h"
+# include "bvh/bvh_embree.h"
/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH. */
-#include "kernel/bvh/bvh_embree.h"
-#include "kernel/kernel_compat_cpu.h"
-#include "kernel/split/kernel_split_data_types.h"
-#include "kernel/kernel_globals.h"
-#include "kernel/kernel_random.h"
-
-#include "render/mesh.h"
-#include "render/object.h"
-#include "util/util_foreach.h"
-#include "util/util_logging.h"
-#include "util/util_progress.h"
+# include "kernel/bvh/bvh_embree.h"
+# include "kernel/kernel_compat_cpu.h"
+# include "kernel/split/kernel_split_data_types.h"
+# include "kernel/kernel_globals.h"
+# include "kernel/kernel_random.h"
+
+# include "render/mesh.h"
+# include "render/object.h"
+# include "util/util_foreach.h"
+# include "util/util_logging.h"
+# include "util/util_progress.h"
CCL_NAMESPACE_BEGIN
-#define IS_HAIR(x) (x & 1)
+# define IS_HAIR(x) (x & 1)
/* This gets called by Embree at every valid ray/object intersection.
* Things like recording subsurface or shadow hits for later evaluation
@@ -64,215 +64,217 @@ CCL_NAMESPACE_BEGIN
*/
static void rtc_filter_func(const RTCFilterFunctionNArguments *args)
{
- /* Current implementation in Cycles assumes only single-ray intersection queries. */
- assert(args->N == 1);
-
- const RTCRay *ray = (RTCRay*)args->ray;
- const RTCHit *hit = (RTCHit*)args->hit;
- CCLIntersectContext *ctx = ((IntersectContext*)args->context)->userRayExt;
- KernelGlobals *kg = ctx->kg;
-
- /* Check if there is backfacing hair to ignore. */
- if(IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
- && !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
- if(dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z), make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
- *args->valid = 0;
- return;
- }
- }
+ /* Current implementation in Cycles assumes only single-ray intersection queries. */
+ assert(args->N == 1);
+
+ const RTCRay *ray = (RTCRay *)args->ray;
+ const RTCHit *hit = (RTCHit *)args->hit;
+ CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
+ KernelGlobals *kg = ctx->kg;
+
+ /* Check if there is backfacing hair to ignore. */
+ if (IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) &&
+ !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING) &&
+ !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
+ if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
+ make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
+ *args->valid = 0;
+ return;
+ }
+ }
}
-static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments* args)
+static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
{
- assert(args->N == 1);
-
- const RTCRay *ray = (RTCRay*)args->ray;
- RTCHit *hit = (RTCHit*)args->hit;
- CCLIntersectContext *ctx = ((IntersectContext*)args->context)->userRayExt;
- KernelGlobals *kg = ctx->kg;
-
- /* For all ray types: Check if there is backfacing hair to ignore */
- if(IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
- && !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
- if(dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z), make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
- *args->valid = 0;
- return;
- }
- }
-
- switch(ctx->type) {
- case CCLIntersectContext::RAY_SHADOW_ALL: {
- /* Append the intersection to the end of the array. */
- if(ctx->num_hits < ctx->max_hits) {
- Intersection current_isect;
- kernel_embree_convert_hit(kg, ray, hit, &current_isect);
- for(size_t i = 0; i < ctx->max_hits; ++i) {
- if(current_isect.object == ctx->isect_s[i].object &&
- current_isect.prim == ctx->isect_s[i].prim &&
- current_isect.t == ctx->isect_s[i].t) {
- /* This intersection was already recorded, skip it. */
- *args->valid = 0;
- break;
- }
- }
- Intersection *isect = &ctx->isect_s[ctx->num_hits];
- ++ctx->num_hits;
- *isect = current_isect;
- int prim = kernel_tex_fetch(__prim_index, isect->prim);
- int shader = 0;
- if(kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
- shader = kernel_tex_fetch(__tri_shader, prim);
- }
- else {
- float4 str = kernel_tex_fetch(__curves, prim);
- shader = __float_as_int(str.z);
- }
- int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
- /* If no transparent shadows, all light is blocked. */
- if(flag & (SD_HAS_TRANSPARENT_SHADOW)) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- }
- }
- else {
- /* Increase the number of hits beyond ray.max_hits
- * so that the caller can detect this as opaque. */
- ++ctx->num_hits;
- }
- break;
- }
- case CCLIntersectContext::RAY_SSS: {
- /* No intersection information requested, just return a hit. */
- if(ctx->max_hits == 0) {
- break;
- }
-
- /* Ignore curves. */
- if(hit->geomID & 1) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
-
- /* See triangle_intersect_subsurface() for the native equivalent. */
- for(int i = min(ctx->max_hits, ctx->ss_isect->num_hits) - 1; i >= 0; --i) {
- if(ctx->ss_isect->hits[i].t == ray->tfar) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
-
- ++ctx->ss_isect->num_hits;
- int hit_idx;
-
- if(ctx->ss_isect->num_hits <= ctx->max_hits) {
- hit_idx = ctx->ss_isect->num_hits - 1;
- }
- else {
- /* reservoir sampling: if we are at the maximum number of
- * hits, randomly replace element or skip it */
- hit_idx = lcg_step_uint(ctx->lcg_state) % ctx->ss_isect->num_hits;
-
- if(hit_idx >= ctx->max_hits) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
- /* record intersection */
- kernel_embree_convert_local_hit(kg, ray, hit, &ctx->ss_isect->hits[hit_idx], ctx->sss_object_id);
- ctx->ss_isect->Ng[hit_idx].x = hit->Ng_x;
- ctx->ss_isect->Ng[hit_idx].y = hit->Ng_y;
- ctx->ss_isect->Ng[hit_idx].z = hit->Ng_z;
- ctx->ss_isect->Ng[hit_idx] = normalize(ctx->ss_isect->Ng[hit_idx]);
- /* This tells Embree to continue tracing .*/
- *args->valid = 0;
- break;
- }
- case CCLIntersectContext::RAY_VOLUME_ALL: {
- /* Append the intersection to the end of the array. */
- if(ctx->num_hits < ctx->max_hits) {
- Intersection current_isect;
- kernel_embree_convert_hit(kg, ray, hit, &current_isect);
- for(size_t i = 0; i < ctx->max_hits; ++i) {
- if(current_isect.object == ctx->isect_s[i].object &&
- current_isect.prim == ctx->isect_s[i].prim &&
- current_isect.t == ctx->isect_s[i].t) {
- /* This intersection was already recorded, skip it. */
- *args->valid = 0;
- break;
- }
- }
- Intersection *isect = &ctx->isect_s[ctx->num_hits];
- ++ctx->num_hits;
- *isect = current_isect;
- /* Only primitives from volume object. */
- uint tri_object = (isect->object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, isect->prim) : isect->object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- --ctx->num_hits;
- }
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
- case CCLIntersectContext::RAY_REGULAR:
- default:
- /* Nothing to do here. */
- break;
- }
+ assert(args->N == 1);
+
+ const RTCRay *ray = (RTCRay *)args->ray;
+ RTCHit *hit = (RTCHit *)args->hit;
+ CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
+ KernelGlobals *kg = ctx->kg;
+
+ /* For all ray types: Check if there is backfacing hair to ignore */
+ if (IS_HAIR(hit->geomID) && (kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) &&
+ !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING) &&
+ !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
+ if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
+ make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
+ *args->valid = 0;
+ return;
+ }
+ }
+
+ switch (ctx->type) {
+ case CCLIntersectContext::RAY_SHADOW_ALL: {
+ /* Append the intersection to the end of the array. */
+ if (ctx->num_hits < ctx->max_hits) {
+ Intersection current_isect;
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+ for (size_t i = 0; i < ctx->max_hits; ++i) {
+ if (current_isect.object == ctx->isect_s[i].object &&
+ current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
+ /* This intersection was already recorded, skip it. */
+ *args->valid = 0;
+ break;
+ }
+ }
+ Intersection *isect = &ctx->isect_s[ctx->num_hits];
+ ++ctx->num_hits;
+ *isect = current_isect;
+ int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ int shader = 0;
+ if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+ else {
+ float4 str = kernel_tex_fetch(__curves, prim);
+ shader = __float_as_int(str.z);
+ }
+ int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
+ /* If no transparent shadows, all light is blocked. */
+ if (flag & (SD_HAS_TRANSPARENT_SHADOW)) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ }
+ }
+ else {
+ /* Increase the number of hits beyond ray.max_hits
+ * so that the caller can detect this as opaque. */
+ ++ctx->num_hits;
+ }
+ break;
+ }
+ case CCLIntersectContext::RAY_SSS: {
+ /* No intersection information requested, just return a hit. */
+ if (ctx->max_hits == 0) {
+ break;
+ }
+
+ /* Ignore curves. */
+ if (hit->geomID & 1) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+
+ /* See triangle_intersect_subsurface() for the native equivalent. */
+ for (int i = min(ctx->max_hits, ctx->ss_isect->num_hits) - 1; i >= 0; --i) {
+ if (ctx->ss_isect->hits[i].t == ray->tfar) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ }
+
+ ++ctx->ss_isect->num_hits;
+ int hit_idx;
+
+ if (ctx->ss_isect->num_hits <= ctx->max_hits) {
+ hit_idx = ctx->ss_isect->num_hits - 1;
+ }
+ else {
+ /* reservoir sampling: if we are at the maximum number of
+ * hits, randomly replace element or skip it */
+ hit_idx = lcg_step_uint(ctx->lcg_state) % ctx->ss_isect->num_hits;
+
+ if (hit_idx >= ctx->max_hits) {
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ }
+ /* record intersection */
+ kernel_embree_convert_local_hit(
+ kg, ray, hit, &ctx->ss_isect->hits[hit_idx], ctx->sss_object_id);
+ ctx->ss_isect->Ng[hit_idx].x = hit->Ng_x;
+ ctx->ss_isect->Ng[hit_idx].y = hit->Ng_y;
+ ctx->ss_isect->Ng[hit_idx].z = hit->Ng_z;
+ ctx->ss_isect->Ng[hit_idx] = normalize(ctx->ss_isect->Ng[hit_idx]);
+ /* This tells Embree to continue tracing .*/
+ *args->valid = 0;
+ break;
+ }
+ case CCLIntersectContext::RAY_VOLUME_ALL: {
+ /* Append the intersection to the end of the array. */
+ if (ctx->num_hits < ctx->max_hits) {
+ Intersection current_isect;
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+ for (size_t i = 0; i < ctx->max_hits; ++i) {
+ if (current_isect.object == ctx->isect_s[i].object &&
+ current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
+ /* This intersection was already recorded, skip it. */
+ *args->valid = 0;
+ break;
+ }
+ }
+ Intersection *isect = &ctx->isect_s[ctx->num_hits];
+ ++ctx->num_hits;
+ *isect = current_isect;
+ /* Only primitives from volume object. */
+ uint tri_object = (isect->object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, isect->prim) :
+ isect->object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ --ctx->num_hits;
+ }
+ /* This tells Embree to continue tracing. */
+ *args->valid = 0;
+ break;
+ }
+ }
+ case CCLIntersectContext::RAY_REGULAR:
+ default:
+ /* Nothing to do here. */
+ break;
+ }
}
static size_t unaccounted_mem = 0;
-static bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool)
+static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
{
- Stats *stats = (Stats*)userPtr;
- if(stats) {
- if(bytes > 0) {
- stats->mem_alloc(bytes);
- }
- else {
- stats->mem_free(-bytes);
- }
- }
- else {
- /* A stats pointer may not yet be available. Keep track of the memory usage for later. */
- if(bytes >= 0) {
- atomic_add_and_fetch_z(&unaccounted_mem, bytes);
- }
- else {
- atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
- }
- }
- return true;
+ Stats *stats = (Stats *)userPtr;
+ if (stats) {
+ if (bytes > 0) {
+ stats->mem_alloc(bytes);
+ }
+ else {
+ stats->mem_free(-bytes);
+ }
+ }
+ else {
+ /* A stats pointer may not yet be available. Keep track of the memory usage for later. */
+ if (bytes >= 0) {
+ atomic_add_and_fetch_z(&unaccounted_mem, bytes);
+ }
+ else {
+ atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
+ }
+ }
+ return true;
}
-static void rtc_error_func(void*, enum RTCError, const char* str)
+static void rtc_error_func(void *, enum RTCError, const char *str)
{
- VLOG(1) << str;
+ VLOG(1) << str;
}
static double progress_start_time = 0.0f;
-static bool rtc_progress_func(void* user_ptr, const double n)
+static bool rtc_progress_func(void *user_ptr, const double n)
{
- Progress *progress = (Progress*)user_ptr;
+ Progress *progress = (Progress *)user_ptr;
- if(time_dt() - progress_start_time < 0.25) {
- return true;
- }
+ if (time_dt() - progress_start_time < 0.25) {
+ return true;
+ }
- string msg = string_printf("Building BVH %.0f%%", n * 100.0);
- progress->set_substatus(msg);
- progress_start_time = time_dt();
+ string msg = string_printf("Building BVH %.0f%%", n * 100.0);
+ progress->set_substatus(msg);
+ progress_start_time = time_dt();
- return !progress->get_cancel();
+ return !progress->get_cancel();
}
/* This is to have a shared device between all BVH instances.
@@ -281,665 +283,679 @@ RTCDevice BVHEmbree::rtc_shared_device = NULL;
int BVHEmbree::rtc_shared_users = 0;
thread_mutex BVHEmbree::rtc_shared_mutex;
-BVHEmbree::BVHEmbree(const BVHParams& params_, const vector<Object*>& objects_)
-: BVH(params_, objects_), scene(NULL), mem_used(0), top_level(NULL), stats(NULL),
- curve_subdivisions(params.curve_subdivisions), build_quality(RTC_BUILD_QUALITY_REFIT),
- use_curves(params_.curve_flags & CURVE_KN_INTERPOLATE),
- use_ribbons(params.curve_flags & CURVE_KN_RIBBONS), dynamic_scene(true)
+BVHEmbree::BVHEmbree(const BVHParams &params_, const vector<Object *> &objects_)
+ : BVH(params_, objects_),
+ scene(NULL),
+ mem_used(0),
+ top_level(NULL),
+ stats(NULL),
+ curve_subdivisions(params.curve_subdivisions),
+ build_quality(RTC_BUILD_QUALITY_REFIT),
+ use_curves(params_.curve_flags & CURVE_KN_INTERPOLATE),
+ use_ribbons(params.curve_flags & CURVE_KN_RIBBONS),
+ dynamic_scene(true)
{
- _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
- _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
- thread_scoped_lock lock(rtc_shared_mutex);
- if(rtc_shared_users == 0) {
- rtc_shared_device = rtcNewDevice("verbose=0");
- /* Check here if Embree was built with the correct flags. */
- ssize_t ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
- if(ret != 1) {
- assert(0);
- VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag."\
- "Ray visiblity will not work.";
- }
- ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
- if(ret != 1) {
- assert(0);
- VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag."\
- "Renders may not look as expected.";
- }
- ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
- if(ret != 1) {
- assert(0);
- VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. "\
- "Line primitives will not be rendered.";
- }
- ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
- if(ret != 1) {
- assert(0);
- VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED flag. "\
- "Triangle primitives will not be rendered.";
- }
- ret = rtcGetDeviceProperty (rtc_shared_device,RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
- if(ret != 0) {
- assert(0);
- VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. "\
- "Renders may not look as expected.";
- }
- }
- ++rtc_shared_users;
-
- rtcSetDeviceErrorFunction(rtc_shared_device, rtc_error_func, NULL);
-
- pack.root_index = -1;
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+ thread_scoped_lock lock(rtc_shared_mutex);
+ if (rtc_shared_users == 0) {
+ rtc_shared_device = rtcNewDevice("verbose=0");
+ /* Check here if Embree was built with the correct flags. */
+ ssize_t ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
+ if (ret != 1) {
+ assert(0);
+ VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag."
+ "Ray visiblity will not work.";
+ }
+ ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
+ if (ret != 1) {
+ assert(0);
+ VLOG(1)
+ << "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag."
+ "Renders may not look as expected.";
+ }
+ ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
+ if (ret != 1) {
+ assert(0);
+ VLOG(1)
+ << "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. "
+ "Line primitives will not be rendered.";
+ }
+ ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
+ if (ret != 1) {
+ assert(0);
+ VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED "
+ "flag. "
+ "Triangle primitives will not be rendered.";
+ }
+ ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
+ if (ret != 0) {
+ assert(0);
+ VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. "
+ "Renders may not look as expected.";
+ }
+ }
+ ++rtc_shared_users;
+
+ rtcSetDeviceErrorFunction(rtc_shared_device, rtc_error_func, NULL);
+
+ pack.root_index = -1;
}
BVHEmbree::~BVHEmbree()
{
- if(!params.top_level) {
- destroy(scene);
- }
+ if (!params.top_level) {
+ destroy(scene);
+ }
}
void BVHEmbree::destroy(RTCScene scene)
{
- if(scene) {
- rtcReleaseScene(scene);
- scene = NULL;
- }
- thread_scoped_lock lock(rtc_shared_mutex);
- --rtc_shared_users;
- if(rtc_shared_users == 0) {
- rtcReleaseDevice (rtc_shared_device);
- rtc_shared_device = NULL;
- }
+ if (scene) {
+ rtcReleaseScene(scene);
+ scene = NULL;
+ }
+ thread_scoped_lock lock(rtc_shared_mutex);
+ --rtc_shared_users;
+ if (rtc_shared_users == 0) {
+ rtcReleaseDevice(rtc_shared_device);
+ rtc_shared_device = NULL;
+ }
}
void BVHEmbree::delete_rtcScene()
{
- if(scene) {
- /* When this BVH is used as an instance in a top level BVH, don't delete now
- * Let the top_level BVH know that it should delete it later. */
- if(top_level) {
- top_level->add_delayed_delete_scene(scene);
- }
- else {
- rtcReleaseScene(scene);
- if(delayed_delete_scenes.size()) {
- foreach(RTCScene s, delayed_delete_scenes) {
- rtcReleaseScene(s);
- }
- }
- delayed_delete_scenes.clear();
- }
- scene = NULL;
- }
+ if (scene) {
+ /* When this BVH is used as an instance in a top level BVH, don't delete now
+ * Let the top_level BVH know that it should delete it later. */
+ if (top_level) {
+ top_level->add_delayed_delete_scene(scene);
+ }
+ else {
+ rtcReleaseScene(scene);
+ if (delayed_delete_scenes.size()) {
+ foreach (RTCScene s, delayed_delete_scenes) {
+ rtcReleaseScene(s);
+ }
+ }
+ delayed_delete_scenes.clear();
+ }
+ scene = NULL;
+ }
}
-void BVHEmbree::build(Progress& progress, Stats *stats_)
+void BVHEmbree::build(Progress &progress, Stats *stats_)
{
- assert(rtc_shared_device);
- stats = stats_;
- rtcSetDeviceMemoryMonitorFunction(rtc_shared_device, rtc_memory_monitor_func, stats);
-
- progress.set_substatus("Building BVH");
-
- if(scene) {
- rtcReleaseScene(scene);
- scene = NULL;
- }
-
- const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
-
- scene = rtcNewScene(rtc_shared_device);
- const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
- RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
- rtcSetSceneFlags(scene, scene_flags);
- build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
- (params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM);
- rtcSetSceneBuildQuality(scene, build_quality);
-
- /* Count triangles and curves first, reserve arrays once. */
- size_t prim_count = 0;
-
- foreach(Object *ob, objects) {
- if (params.top_level) {
- if (!ob->is_traceable()) {
- continue;
- }
- if (!ob->mesh->is_instanced()) {
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
- prim_count += ob->mesh->num_triangles();
- }
- if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
- for (size_t j = 0; j < ob->mesh->num_curves(); ++j) {
- prim_count += ob->mesh->get_curve(j).num_segments();
- }
- }
- }
- else {
- ++prim_count;
- }
- }
- else {
- if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
- prim_count += ob->mesh->num_triangles();
- }
- if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
- for (size_t j = 0; j < ob->mesh->num_curves(); ++j) {
- prim_count += ob->mesh->get_curve(j).num_segments();
- }
- }
- }
- }
-
- pack.prim_object.reserve(prim_count);
- pack.prim_type.reserve(prim_count);
- pack.prim_index.reserve(prim_count);
- pack.prim_tri_index.reserve(prim_count);
-
- int i = 0;
-
- pack.object_node.clear();
-
- foreach(Object *ob, objects) {
- if(params.top_level) {
- if(!ob->is_traceable()) {
- ++i;
- continue;
- }
- if(!ob->mesh->is_instanced()) {
- add_object(ob, i);
- }
- else {
- add_instance(ob, i);
- }
- }
- else {
- add_object(ob, i);
- }
- ++i;
- if(progress.get_cancel()) return;
- }
-
- if(progress.get_cancel()) {
- delete_rtcScene();
- stats = NULL;
- return;
- }
-
- rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
- rtcCommitScene(scene);
-
- pack_primitives();
-
- if(progress.get_cancel()) {
- delete_rtcScene();
- stats = NULL;
- return;
- }
-
- progress.set_substatus("Packing geometry");
- pack_nodes(NULL);
-
- stats = NULL;
+ assert(rtc_shared_device);
+ stats = stats_;
+ rtcSetDeviceMemoryMonitorFunction(rtc_shared_device, rtc_memory_monitor_func, stats);
+
+ progress.set_substatus("Building BVH");
+
+ if (scene) {
+ rtcReleaseScene(scene);
+ scene = NULL;
+ }
+
+ const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
+
+ scene = rtcNewScene(rtc_shared_device);
+ const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
+ RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
+ rtcSetSceneFlags(scene, scene_flags);
+ build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
+ (params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
+ RTC_BUILD_QUALITY_MEDIUM);
+ rtcSetSceneBuildQuality(scene, build_quality);
+
+ /* Count triangles and curves first, reserve arrays once. */
+ size_t prim_count = 0;
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ continue;
+ }
+ if (!ob->mesh->is_instanced()) {
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ prim_count += ob->mesh->num_triangles();
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ for (size_t j = 0; j < ob->mesh->num_curves(); ++j) {
+ prim_count += ob->mesh->get_curve(j).num_segments();
+ }
+ }
+ }
+ else {
+ ++prim_count;
+ }
+ }
+ else {
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
+ prim_count += ob->mesh->num_triangles();
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ for (size_t j = 0; j < ob->mesh->num_curves(); ++j) {
+ prim_count += ob->mesh->get_curve(j).num_segments();
+ }
+ }
+ }
+ }
+
+ pack.prim_object.reserve(prim_count);
+ pack.prim_type.reserve(prim_count);
+ pack.prim_index.reserve(prim_count);
+ pack.prim_tri_index.reserve(prim_count);
+
+ int i = 0;
+
+ pack.object_node.clear();
+
+ foreach (Object *ob, objects) {
+ if (params.top_level) {
+ if (!ob->is_traceable()) {
+ ++i;
+ continue;
+ }
+ if (!ob->mesh->is_instanced()) {
+ add_object(ob, i);
+ }
+ else {
+ add_instance(ob, i);
+ }
+ }
+ else {
+ add_object(ob, i);
+ }
+ ++i;
+ if (progress.get_cancel())
+ return;
+ }
+
+ if (progress.get_cancel()) {
+ delete_rtcScene();
+ stats = NULL;
+ return;
+ }
+
+ rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
+ rtcCommitScene(scene);
+
+ pack_primitives();
+
+ if (progress.get_cancel()) {
+ delete_rtcScene();
+ stats = NULL;
+ return;
+ }
+
+ progress.set_substatus("Packing geometry");
+ pack_nodes(NULL);
+
+ stats = NULL;
}
BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/)
{
- assert(!"Must not be called.");
- return NULL;
+ assert(!"Must not be called.");
+ return NULL;
}
void BVHEmbree::add_object(Object *ob, int i)
{
- Mesh *mesh = ob->mesh;
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
- add_triangles(ob, i);
- }
- if(params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
- add_curves(ob, i);
- }
+ Mesh *mesh = ob->mesh;
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
+ add_triangles(ob, i);
+ }
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
+ add_curves(ob, i);
+ }
}
void BVHEmbree::add_instance(Object *ob, int i)
{
- if(!ob || !ob->mesh) {
- assert(0);
- return;
- }
- BVHEmbree *instance_bvh = (BVHEmbree*)(ob->mesh->bvh);
-
- if(instance_bvh->top_level != this) {
- instance_bvh->top_level = this;
- }
-
- const size_t num_motion_steps = ob->use_motion() ? ob->motion.size() : 1;
- RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_INSTANCE);
- rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- if(ob->use_motion()) {
- for(size_t step = 0; step < num_motion_steps; ++step) {
- rtcSetGeometryTransform(geom_id, step, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*)&ob->motion[step]);
- }
- }
- else {
- rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*)&ob->tfm);
- }
-
- pack.prim_index.push_back_slow(-1);
- pack.prim_object.push_back_slow(i);
- pack.prim_type.push_back_slow(PRIMITIVE_NONE);
- pack.prim_tri_index.push_back_slow(-1);
-
- rtcSetGeometryUserData(geom_id, (void*) instance_bvh->scene);
- rtcSetGeometryMask(geom_id, ob->visibility);
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i*2);
- rtcReleaseGeometry(geom_id);
+ if (!ob || !ob->mesh) {
+ assert(0);
+ return;
+ }
+ BVHEmbree *instance_bvh = (BVHEmbree *)(ob->mesh->bvh);
+
+ if (instance_bvh->top_level != this) {
+ instance_bvh->top_level = this;
+ }
+
+ const size_t num_motion_steps = ob->use_motion() ? ob->motion.size() : 1;
+ RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_INSTANCE);
+ rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ if (ob->use_motion()) {
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ rtcSetGeometryTransform(
+ geom_id, step, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->motion[step]);
+ }
+ }
+ else {
+ rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->tfm);
+ }
+
+ pack.prim_index.push_back_slow(-1);
+ pack.prim_object.push_back_slow(i);
+ pack.prim_type.push_back_slow(PRIMITIVE_NONE);
+ pack.prim_tri_index.push_back_slow(-1);
+
+ rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
+ rtcSetGeometryMask(geom_id, ob->visibility);
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
}
void BVHEmbree::add_triangles(Object *ob, int i)
{
- size_t prim_offset = pack.prim_index.size();
- Mesh *mesh = ob->mesh;
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if(mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr_mP) {
- num_motion_steps = mesh->motion_steps;
- if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
- assert(0);
- num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
- }
- }
- }
-
- const size_t num_triangles = mesh->num_triangles();
- RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_TRIANGLE);
- rtcSetGeometryBuildQuality(geom_id, build_quality);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- unsigned *rtc_indices = (unsigned*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0,
- RTC_FORMAT_UINT3, sizeof (int) * 3, num_triangles);
- assert(rtc_indices);
- if(!rtc_indices) {
- VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str() << ".\n";
- return;
- }
- for(size_t j = 0; j < num_triangles; ++j) {
- Mesh::Triangle t = mesh->get_triangle(j);
- rtc_indices[j*3] = t.v[0];
- rtc_indices[j*3+1] = t.v[1];
- rtc_indices[j*3+2] = t.v[2];
- }
-
- update_tri_vertex_buffer(geom_id, mesh);
-
- size_t prim_object_size = pack.prim_object.size();
- pack.prim_object.resize(prim_object_size + num_triangles);
- size_t prim_type_size = pack.prim_type.size();
- pack.prim_type.resize(prim_type_size + num_triangles);
- size_t prim_index_size = pack.prim_index.size();
- pack.prim_index.resize(prim_index_size + num_triangles);
- pack.prim_tri_index.resize(prim_index_size + num_triangles);
- int prim_type = (num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
-
- for(size_t j = 0; j < num_triangles; ++j) {
- pack.prim_object[prim_object_size + j] = i;
- pack.prim_type[prim_type_size + j] = prim_type;
- pack.prim_index[prim_index_size + j] = j;
- pack.prim_tri_index[prim_index_size + j] = j;
- }
-
- rtcSetGeometryUserData(geom_id, (void*) prim_offset);
- rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
- rtcSetGeometryMask(geom_id, ob->visibility);
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i*2);
- rtcReleaseGeometry(geom_id);
+ size_t prim_offset = pack.prim_index.size();
+ Mesh *mesh = ob->mesh;
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->motion_steps;
+ if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
+ assert(0);
+ num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
+ }
+ }
+ }
+
+ const size_t num_triangles = mesh->num_triangles();
+ RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
+ assert(rtc_indices);
+ if (!rtc_indices) {
+ VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
+ << ".\n";
+ return;
+ }
+ for (size_t j = 0; j < num_triangles; ++j) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ rtc_indices[j * 3] = t.v[0];
+ rtc_indices[j * 3 + 1] = t.v[1];
+ rtc_indices[j * 3 + 2] = t.v[2];
+ }
+
+ update_tri_vertex_buffer(geom_id, mesh);
+
+ size_t prim_object_size = pack.prim_object.size();
+ pack.prim_object.resize(prim_object_size + num_triangles);
+ size_t prim_type_size = pack.prim_type.size();
+ pack.prim_type.resize(prim_type_size + num_triangles);
+ size_t prim_index_size = pack.prim_index.size();
+ pack.prim_index.resize(prim_index_size + num_triangles);
+ pack.prim_tri_index.resize(prim_index_size + num_triangles);
+ int prim_type = (num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
+
+ for (size_t j = 0; j < num_triangles; ++j) {
+ pack.prim_object[prim_object_size + j] = i;
+ pack.prim_type[prim_type_size + j] = prim_type;
+ pack.prim_index[prim_index_size + j] = j;
+ pack.prim_tri_index[prim_index_size + j] = j;
+ }
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
+ rtcSetGeometryMask(geom_id, ob->visibility);
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
}
-void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh)
+void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh)
{
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- int t_mid = 0;
- if(mesh->has_motion_blur()) {
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr_mP) {
- num_motion_steps = mesh->motion_steps;
- t_mid = (num_motion_steps - 1) / 2;
- if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
- assert(0);
- num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
- }
- }
- }
- const size_t num_verts = mesh->verts.size();
-
- for(int t = 0; t < num_motion_steps; ++t) {
- const float3 *verts;
- if(t == t_mid) {
- verts = &mesh->verts[0];
- }
- else {
- int t_ = (t > t_mid) ? (t - 1) : t;
- verts = &attr_mP->data_float3()[t_ * num_verts];
- }
-
- float *rtc_verts = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t,
- RTC_FORMAT_FLOAT3, sizeof(float) * 3, num_verts + 1);
- assert(rtc_verts);
- if(rtc_verts) {
- for(size_t j = 0; j < num_verts; ++j) {
- rtc_verts[0] = verts[j].x;
- rtc_verts[1] = verts[j].y;
- rtc_verts[2] = verts[j].z;
- rtc_verts += 3;
- }
- }
- }
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ int t_mid = 0;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->motion_steps;
+ t_mid = (num_motion_steps - 1) / 2;
+ if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
+ assert(0);
+ num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
+ }
+ }
+ }
+ const size_t num_verts = mesh->verts.size();
+
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid) {
+ verts = &mesh->verts[0];
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_verts];
+ }
+
+ float *rtc_verts = (float *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_VERTEX, t, RTC_FORMAT_FLOAT3, sizeof(float) * 3, num_verts + 1);
+ assert(rtc_verts);
+ if (rtc_verts) {
+ for (size_t j = 0; j < num_verts; ++j) {
+ rtc_verts[0] = verts[j].x;
+ rtc_verts[1] = verts[j].y;
+ rtc_verts[2] = verts[j].z;
+ rtc_verts += 3;
+ }
+ }
+ }
}
-void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh)
+void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh)
{
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if(mesh->has_motion_blur()) {
- attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr_mP) {
- num_motion_steps = mesh->motion_steps;
- }
- }
-
- const size_t num_curves = mesh->num_curves();
- size_t num_keys = 0;
- for(size_t j = 0; j < num_curves; ++j) {
- const Mesh::Curve c = mesh->get_curve(j);
- num_keys += c.num_keys;
- }
-
- /* Copy the CV data to Embree */
- const int t_mid = (num_motion_steps - 1) / 2;
- const float *curve_radius = &mesh->curve_radius[0];
- for(int t = 0; t < num_motion_steps; ++t) {
- const float3 *verts;
- if(t == t_mid || attr_mP == NULL) {
- verts = &mesh->curve_keys[0];
- }
- else {
- int t_ = (t > t_mid) ? (t - 1) : t;
- verts = &attr_mP->data_float3()[t_ * num_keys];
- }
-
- float4 *rtc_verts = (float4*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t,
- RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
- float4 *rtc_tangents = NULL;
- if(use_curves) {
- rtc_tangents = (float4*)rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_TANGENT, t,
- RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
- assert(rtc_tangents);
- }
- assert(rtc_verts);
- if(rtc_verts) {
- if(use_curves && rtc_tangents) {
- const size_t num_curves = mesh->num_curves();
- for(size_t j = 0; j < num_curves; ++j) {
- Mesh::Curve c = mesh->get_curve(j);
- int fk = c.first_key;
- rtc_verts[0] = float3_to_float4(verts[fk]);
- rtc_verts[0].w = curve_radius[fk];
- rtc_tangents[0] = float3_to_float4(verts[fk + 1] - verts[fk]);
- rtc_tangents[0].w = curve_radius[fk + 1] - curve_radius[fk];
- ++fk;
- int k = 1;
- for(;k < c.num_segments(); ++k, ++fk) {
- rtc_verts[k] = float3_to_float4(verts[fk]);
- rtc_verts[k].w = curve_radius[fk];
- rtc_tangents[k] = float3_to_float4((verts[fk + 1] - verts[fk - 1]) * 0.5f);
- rtc_tangents[k].w = (curve_radius[fk + 1] - curve_radius[fk - 1]) * 0.5f;
- }
- rtc_verts[k] = float3_to_float4(verts[fk]);
- rtc_verts[k].w = curve_radius[fk];
- rtc_tangents[k] = float3_to_float4(verts[fk] - verts[fk - 1]);
- rtc_tangents[k].w = curve_radius[fk] - curve_radius[fk - 1];
- rtc_verts += c.num_keys;
- rtc_tangents += c.num_keys;
- }
- }
- else {
- for(size_t j = 0; j < num_keys; ++j) {
- rtc_verts[j] = float3_to_float4(verts[j]);
- rtc_verts[j].w = curve_radius[j];
- }
- }
- }
- }
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->motion_steps;
+ }
+ }
+
+ const size_t num_curves = mesh->num_curves();
+ size_t num_keys = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ const Mesh::Curve c = mesh->get_curve(j);
+ num_keys += c.num_keys;
+ }
+
+ /* Copy the CV data to Embree */
+ const int t_mid = (num_motion_steps - 1) / 2;
+ const float *curve_radius = &mesh->curve_radius[0];
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid || attr_mP == NULL) {
+ verts = &mesh->curve_keys[0];
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_keys];
+ }
+
+ float4 *rtc_verts = (float4 *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_VERTEX, t, RTC_FORMAT_FLOAT4, sizeof(float) * 4, num_keys);
+ float4 *rtc_tangents = NULL;
+ if (use_curves) {
+ rtc_tangents = (float4 *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_TANGENT, t, RTC_FORMAT_FLOAT4, sizeof(float) * 4, num_keys);
+ assert(rtc_tangents);
+ }
+ assert(rtc_verts);
+ if (rtc_verts) {
+ if (use_curves && rtc_tangents) {
+ const size_t num_curves = mesh->num_curves();
+ for (size_t j = 0; j < num_curves; ++j) {
+ Mesh::Curve c = mesh->get_curve(j);
+ int fk = c.first_key;
+ rtc_verts[0] = float3_to_float4(verts[fk]);
+ rtc_verts[0].w = curve_radius[fk];
+ rtc_tangents[0] = float3_to_float4(verts[fk + 1] - verts[fk]);
+ rtc_tangents[0].w = curve_radius[fk + 1] - curve_radius[fk];
+ ++fk;
+ int k = 1;
+ for (; k < c.num_segments(); ++k, ++fk) {
+ rtc_verts[k] = float3_to_float4(verts[fk]);
+ rtc_verts[k].w = curve_radius[fk];
+ rtc_tangents[k] = float3_to_float4((verts[fk + 1] - verts[fk - 1]) * 0.5f);
+ rtc_tangents[k].w = (curve_radius[fk + 1] - curve_radius[fk - 1]) * 0.5f;
+ }
+ rtc_verts[k] = float3_to_float4(verts[fk]);
+ rtc_verts[k].w = curve_radius[fk];
+ rtc_tangents[k] = float3_to_float4(verts[fk] - verts[fk - 1]);
+ rtc_tangents[k].w = curve_radius[fk] - curve_radius[fk - 1];
+ rtc_verts += c.num_keys;
+ rtc_tangents += c.num_keys;
+ }
+ }
+ else {
+ for (size_t j = 0; j < num_keys; ++j) {
+ rtc_verts[j] = float3_to_float4(verts[j]);
+ rtc_verts[j].w = curve_radius[j];
+ }
+ }
+ }
+ }
}
void BVHEmbree::add_curves(Object *ob, int i)
{
- size_t prim_offset = pack.prim_index.size();
- const Mesh *mesh = ob->mesh;
- const Attribute *attr_mP = NULL;
- size_t num_motion_steps = 1;
- if(mesh->has_motion_blur()) {
- attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr_mP) {
- num_motion_steps = mesh->motion_steps;
- }
- }
-
- const size_t num_curves = mesh->num_curves();
- size_t num_segments = 0;
- for(size_t j = 0; j < num_curves; ++j) {
- Mesh::Curve c = mesh->get_curve(j);
- assert(c.num_segments() > 0);
- num_segments += c.num_segments();
- }
-
- /* Make room for Cycles specific data. */
- size_t prim_object_size = pack.prim_object.size();
- pack.prim_object.resize(prim_object_size + num_segments);
- size_t prim_type_size = pack.prim_type.size();
- pack.prim_type.resize(prim_type_size + num_segments);
- size_t prim_index_size = pack.prim_index.size();
- pack.prim_index.resize(prim_index_size + num_segments);
- size_t prim_tri_index_size = pack.prim_index.size();
- pack.prim_tri_index.resize(prim_tri_index_size + num_segments);
-
- enum RTCGeometryType type = (!use_curves) ? RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE :
- (use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE :
- RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE);
-
- RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, type);
- rtcSetGeometryTessellationRate(geom_id, curve_subdivisions);
- unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0,
- RTC_FORMAT_UINT, sizeof (int), num_segments);
- size_t rtc_index = 0;
- for(size_t j = 0; j < num_curves; ++j) {
- Mesh::Curve c = mesh->get_curve(j);
- for(size_t k = 0; k < c.num_segments(); ++k) {
- rtc_indices[rtc_index] = c.first_key + k;
- /* Cycles specific data. */
- pack.prim_object[prim_object_size + rtc_index] = i;
- pack.prim_type[prim_type_size + rtc_index] = (PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ?
- PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
- pack.prim_index[prim_index_size + rtc_index] = j;
- pack.prim_tri_index[prim_tri_index_size + rtc_index] = rtc_index;
-
- ++rtc_index;
- }
- }
-
- rtcSetGeometryBuildQuality(geom_id, build_quality);
- rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
-
- update_curve_vertex_buffer(geom_id, mesh);
-
- rtcSetGeometryUserData(geom_id, (void*) prim_offset);
- rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
- rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
- rtcSetGeometryMask(geom_id, ob->visibility);
-
- rtcCommitGeometry(geom_id);
- rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
- rtcReleaseGeometry(geom_id);
+ size_t prim_offset = pack.prim_index.size();
+ const Mesh *mesh = ob->mesh;
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (mesh->has_motion_blur()) {
+ attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = mesh->motion_steps;
+ }
+ }
+
+ const size_t num_curves = mesh->num_curves();
+ size_t num_segments = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ Mesh::Curve c = mesh->get_curve(j);
+ assert(c.num_segments() > 0);
+ num_segments += c.num_segments();
+ }
+
+ /* Make room for Cycles specific data. */
+ size_t prim_object_size = pack.prim_object.size();
+ pack.prim_object.resize(prim_object_size + num_segments);
+ size_t prim_type_size = pack.prim_type.size();
+ pack.prim_type.resize(prim_type_size + num_segments);
+ size_t prim_index_size = pack.prim_index.size();
+ pack.prim_index.resize(prim_index_size + num_segments);
+ size_t prim_tri_index_size = pack.prim_index.size();
+ pack.prim_tri_index.resize(prim_tri_index_size + num_segments);
+
+ enum RTCGeometryType type = (!use_curves) ?
+ RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE :
+ (use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE :
+ RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE);
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, type);
+ rtcSetGeometryTessellationRate(geom_id, curve_subdivisions);
+ unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
+ geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);
+ size_t rtc_index = 0;
+ for (size_t j = 0; j < num_curves; ++j) {
+ Mesh::Curve c = mesh->get_curve(j);
+ for (size_t k = 0; k < c.num_segments(); ++k) {
+ rtc_indices[rtc_index] = c.first_key + k;
+ /* Cycles specific data. */
+ pack.prim_object[prim_object_size + rtc_index] = i;
+ pack.prim_type[prim_type_size + rtc_index] = (PRIMITIVE_PACK_SEGMENT(
+ num_motion_steps > 1 ? PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
+ pack.prim_index[prim_index_size + rtc_index] = j;
+ pack.prim_tri_index[prim_tri_index_size + rtc_index] = rtc_index;
+
+ ++rtc_index;
+ }
+ }
+
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ update_curve_vertex_buffer(geom_id, mesh);
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
+ rtcSetGeometryMask(geom_id, ob->visibility);
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
+ rtcReleaseGeometry(geom_id);
}
void BVHEmbree::pack_nodes(const BVHNode *)
{
- /* Quite a bit of this code is for compatibility with Cycles' native BVH. */
- if(!params.top_level) {
- return;
- }
-
- for(size_t i = 0; i < pack.prim_index.size(); ++i) {
- if(pack.prim_index[i] != -1) {
- if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
- pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
- else
- pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
- }
- }
-
- size_t prim_offset = pack.prim_index.size();
-
- /* reserve */
- size_t prim_index_size = pack.prim_index.size();
- size_t prim_tri_verts_size = pack.prim_tri_verts.size();
-
- size_t pack_prim_index_offset = prim_index_size;
- size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
- size_t object_offset = 0;
-
- map<Mesh*, int> mesh_map;
-
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
- BVH *bvh = mesh->bvh;
-
- if(mesh->need_build_bvh()) {
- if(mesh_map.find(mesh) == mesh_map.end()) {
- prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
- mesh_map[mesh] = 1;
- }
- }
- }
-
- mesh_map.clear();
-
- pack.prim_index.resize(prim_index_size);
- pack.prim_type.resize(prim_index_size);
- pack.prim_object.resize(prim_index_size);
- pack.prim_visibility.clear();
- pack.prim_tri_verts.resize(prim_tri_verts_size);
- pack.prim_tri_index.resize(prim_index_size);
- pack.object_node.resize(objects.size());
-
- int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
- int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
- int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
- float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL;
- uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL;
-
- /* merge */
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
-
- /* We assume that if mesh doesn't need own BVH it was already included
- * into a top-level BVH and no packing here is needed.
- */
- if(!mesh->need_build_bvh()) {
- pack.object_node[object_offset++] = prim_offset;
- continue;
- }
-
- /* if mesh already added once, don't add it again, but used set
- * node offset for this object */
- map<Mesh*, int>::iterator it = mesh_map.find(mesh);
-
- if(mesh_map.find(mesh) != mesh_map.end()) {
- int noffset = it->second;
- pack.object_node[object_offset++] = noffset;
- continue;
- }
-
- BVHEmbree *bvh = (BVHEmbree*)mesh->bvh;
-
- rtc_memory_monitor_func(stats, unaccounted_mem, true);
- unaccounted_mem = 0;
-
- int mesh_tri_offset = mesh->tri_offset;
- int mesh_curve_offset = mesh->curve_offset;
-
- /* fill in node indexes for instances */
- pack.object_node[object_offset++] = prim_offset;
-
- mesh_map[mesh] = pack.object_node[object_offset-1];
-
- /* merge primitive, object and triangle indexes */
- if(bvh->pack.prim_index.size()) {
- size_t bvh_prim_index_size = bvh->pack.prim_index.size();
- int *bvh_prim_index = &bvh->pack.prim_index[0];
- int *bvh_prim_type = &bvh->pack.prim_type[0];
- uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
-
- for(size_t i = 0; i < bvh_prim_index_size; ++i) {
- if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
- pack_prim_tri_index[pack_prim_index_offset] = -1;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
- pack_prim_tri_index[pack_prim_index_offset] =
- bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
- }
-
- pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
- pack_prim_object[pack_prim_index_offset] = 0;
-
- ++pack_prim_index_offset;
- }
- }
-
- /* Merge triangle vertices data. */
- if(bvh->pack.prim_tri_verts.size()) {
- const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
- memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
- &bvh->pack.prim_tri_verts[0],
- prim_tri_size*sizeof(float4));
- pack_prim_tri_verts_offset += prim_tri_size;
- }
-
- prim_offset += bvh->pack.prim_index.size();
- }
+ /* Quite a bit of this code is for compatibility with Cycles' native BVH. */
+ if (!params.top_level) {
+ return;
+ }
+
+ for (size_t i = 0; i < pack.prim_index.size(); ++i) {
+ if (pack.prim_index[i] != -1) {
+ if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
+ else
+ pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+ }
+ }
+
+ size_t prim_offset = pack.prim_index.size();
+
+ /* reserve */
+ size_t prim_index_size = pack.prim_index.size();
+ size_t prim_tri_verts_size = pack.prim_tri_verts.size();
+
+ size_t pack_prim_index_offset = prim_index_size;
+ size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
+ size_t object_offset = 0;
+
+ map<Mesh *, int> mesh_map;
+
+ foreach (Object *ob, objects) {
+ Mesh *mesh = ob->mesh;
+ BVH *bvh = mesh->bvh;
+
+ if (mesh->need_build_bvh()) {
+ if (mesh_map.find(mesh) == mesh_map.end()) {
+ prim_index_size += bvh->pack.prim_index.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+ mesh_map[mesh] = 1;
+ }
+ }
+ }
+
+ mesh_map.clear();
+
+ pack.prim_index.resize(prim_index_size);
+ pack.prim_type.resize(prim_index_size);
+ pack.prim_object.resize(prim_index_size);
+ pack.prim_visibility.clear();
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ pack.prim_tri_index.resize(prim_index_size);
+ pack.object_node.resize(objects.size());
+
+ int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : NULL;
+ int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
+ int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
+ float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
+ uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
+
+ /* merge */
+ foreach (Object *ob, objects) {
+ Mesh *mesh = ob->mesh;
+
+ /* We assume that if mesh doesn't need own BVH it was already included
+ * into a top-level BVH and no packing here is needed.
+ */
+ if (!mesh->need_build_bvh()) {
+ pack.object_node[object_offset++] = prim_offset;
+ continue;
+ }
+
+ /* if mesh already added once, don't add it again, but used set
+ * node offset for this object */
+ map<Mesh *, int>::iterator it = mesh_map.find(mesh);
+
+ if (mesh_map.find(mesh) != mesh_map.end()) {
+ int noffset = it->second;
+ pack.object_node[object_offset++] = noffset;
+ continue;
+ }
+
+ BVHEmbree *bvh = (BVHEmbree *)mesh->bvh;
+
+ rtc_memory_monitor_func(stats, unaccounted_mem, true);
+ unaccounted_mem = 0;
+
+ int mesh_tri_offset = mesh->tri_offset;
+ int mesh_curve_offset = mesh->curve_offset;
+
+ /* fill in node indexes for instances */
+ pack.object_node[object_offset++] = prim_offset;
+
+ mesh_map[mesh] = pack.object_node[object_offset - 1];
+
+ /* merge primitive, object and triangle indexes */
+ if (bvh->pack.prim_index.size()) {
+ size_t bvh_prim_index_size = bvh->pack.prim_index.size();
+ int *bvh_prim_index = &bvh->pack.prim_index[0];
+ int *bvh_prim_type = &bvh->pack.prim_type[0];
+ uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
+
+ for (size_t i = 0; i < bvh_prim_index_size; ++i) {
+ if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = -1;
+ }
+ else {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
+ pack_prim_tri_verts_offset;
+ }
+
+ pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
+ pack_prim_object[pack_prim_index_offset] = 0;
+
+ ++pack_prim_index_offset;
+ }
+ }
+
+ /* Merge triangle vertices data. */
+ if (bvh->pack.prim_tri_verts.size()) {
+ const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+ &bvh->pack.prim_tri_verts[0],
+ prim_tri_size * sizeof(float4));
+ pack_prim_tri_verts_offset += prim_tri_size;
+ }
+
+ prim_offset += bvh->pack.prim_index.size();
+ }
}
void BVHEmbree::refit_nodes()
{
- /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
- unsigned geom_id = 0;
- foreach(Object *ob, objects) {
- if(!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) {
- if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
- update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh);
- rtcCommitGeometry(rtcGetGeometry(scene,geom_id));
- }
-
- if(params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
- update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id+1), ob->mesh);
- rtcCommitGeometry(rtcGetGeometry(scene,geom_id+1));
- }
- }
- geom_id += 2;
- }
- rtcCommitScene(scene);
+ /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
+ unsigned geom_id = 0;
+ foreach (Object *ob, objects) {
+ if (!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) {
+ if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
+ update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh);
+ rtcCommitGeometry(rtcGetGeometry(scene, geom_id));
+ }
+
+ if (params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
+ update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id + 1), ob->mesh);
+ rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1));
+ }
+ }
+ geom_id += 2;
+ }
+ rtcCommitScene(scene);
}
CCL_NAMESPACE_END
-#endif /* WITH_EMBREE */
+#endif /* WITH_EMBREE */
diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h
index 983b6dc07da..60702713583 100644
--- a/intern/cycles/bvh/bvh_embree.h
+++ b/intern/cycles/bvh/bvh_embree.h
@@ -19,65 +19,68 @@
#ifdef WITH_EMBREE
-#include <embree3/rtcore.h>
-#include <embree3/rtcore_scene.h>
+# include <embree3/rtcore.h>
+# include <embree3/rtcore_scene.h>
-#include "bvh/bvh.h"
-#include "bvh/bvh_params.h"
+# include "bvh/bvh.h"
+# include "bvh/bvh_params.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-#include "util/util_vector.h"
+# include "util/util_thread.h"
+# include "util/util_types.h"
+# include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
class Mesh;
-class BVHEmbree : public BVH
-{
-public:
- virtual void build(Progress& progress, Stats *stats) override;
- virtual ~BVHEmbree();
- RTCScene scene;
- static void destroy(RTCScene);
-
- /* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
-
-protected:
- friend class BVH;
- BVHEmbree(const BVHParams& params, const vector<Object*>& objects);
-
- virtual void pack_nodes(const BVHNode*) override;
- virtual void refit_nodes() override;
-
- void add_object(Object *ob, int i);
- void add_instance(Object *ob, int i);
- void add_curves(Object *ob, int i);
- void add_triangles(Object *ob, int i);
-
- ssize_t mem_used;
-
- void add_delayed_delete_scene(RTCScene scene) { delayed_delete_scenes.push_back(scene); }
- BVHEmbree *top_level;
-private:
- void delete_rtcScene();
- void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh);
- void update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh);
-
- static RTCDevice rtc_shared_device;
- static int rtc_shared_users;
- static thread_mutex rtc_shared_mutex;
-
- Stats *stats;
- vector<RTCScene> delayed_delete_scenes;
- int curve_subdivisions;
- enum RTCBuildQuality build_quality;
- bool use_curves, use_ribbons, dynamic_scene;
+class BVHEmbree : public BVH {
+ public:
+ virtual void build(Progress &progress, Stats *stats) override;
+ virtual ~BVHEmbree();
+ RTCScene scene;
+ static void destroy(RTCScene);
+
+ /* Building process. */
+ virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+
+ protected:
+ friend class BVH;
+ BVHEmbree(const BVHParams &params, const vector<Object *> &objects);
+
+ virtual void pack_nodes(const BVHNode *) override;
+ virtual void refit_nodes() override;
+
+ void add_object(Object *ob, int i);
+ void add_instance(Object *ob, int i);
+ void add_curves(Object *ob, int i);
+ void add_triangles(Object *ob, int i);
+
+ ssize_t mem_used;
+
+ void add_delayed_delete_scene(RTCScene scene)
+ {
+ delayed_delete_scenes.push_back(scene);
+ }
+ BVHEmbree *top_level;
+
+ private:
+ void delete_rtcScene();
+ void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh);
+ void update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh);
+
+ static RTCDevice rtc_shared_device;
+ static int rtc_shared_users;
+ static thread_mutex rtc_shared_mutex;
+
+ Stats *stats;
+ vector<RTCScene> delayed_delete_scenes;
+ int curve_subdivisions;
+ enum RTCBuildQuality build_quality;
+ bool use_curves, use_ribbons, dynamic_scene;
};
CCL_NAMESPACE_END
-#endif /* WITH_EMBREE */
+#endif /* WITH_EMBREE */
-#endif /* __BVH_EMBREE_H__ */
+#endif /* __BVH_EMBREE_H__ */
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
index 614fb6be88a..38b554acfbf 100644
--- a/intern/cycles/bvh/bvh_node.cpp
+++ b/intern/cycles/bvh/bvh_node.cpp
@@ -28,199 +28,197 @@ CCL_NAMESPACE_BEGIN
int BVHNode::getSubtreeSize(BVH_STAT stat) const
{
- int cnt = 0;
-
- switch(stat)
- {
- case BVH_STAT_NODE_COUNT:
- cnt = 1;
- break;
- case BVH_STAT_LEAF_COUNT:
- cnt = is_leaf() ? 1 : 0;
- break;
- case BVH_STAT_INNER_COUNT:
- cnt = is_leaf() ? 0 : 1;
- break;
- case BVH_STAT_TRIANGLE_COUNT:
- cnt = is_leaf() ? reinterpret_cast<const LeafNode*>(this)->num_triangles() : 0;
- break;
- case BVH_STAT_CHILDNODE_COUNT:
- cnt = num_children();
- break;
- case BVH_STAT_ALIGNED_COUNT:
- if(!is_unaligned) {
- cnt = 1;
- }
- break;
- case BVH_STAT_UNALIGNED_COUNT:
- if(is_unaligned) {
- cnt = 1;
- }
- break;
- case BVH_STAT_ALIGNED_INNER_COUNT:
- if(!is_leaf()) {
- bool has_unaligned = false;
- for(int j = 0; j < num_children(); j++) {
- has_unaligned |= get_child(j)->is_unaligned;
- }
- cnt += has_unaligned? 0: 1;
- }
- break;
- case BVH_STAT_UNALIGNED_INNER_COUNT:
- if(!is_leaf()) {
- bool has_unaligned = false;
- for(int j = 0; j < num_children(); j++) {
- has_unaligned |= get_child(j)->is_unaligned;
- }
- cnt += has_unaligned? 1: 0;
- }
- break;
- case BVH_STAT_ALIGNED_LEAF_COUNT:
- cnt = (is_leaf() && !is_unaligned) ? 1 : 0;
- break;
- case BVH_STAT_UNALIGNED_LEAF_COUNT:
- cnt = (is_leaf() && is_unaligned) ? 1 : 0;
- break;
- case BVH_STAT_DEPTH:
- if(is_leaf()) {
- cnt = 1;
- }
- else {
- for(int i = 0; i < num_children(); i++) {
- cnt = max(cnt, get_child(i)->getSubtreeSize(stat));
- }
- cnt += 1;
- }
- return cnt;
- default:
- assert(0); /* unknown mode */
- }
-
- if(!is_leaf())
- for(int i = 0; i < num_children(); i++)
- cnt += get_child(i)->getSubtreeSize(stat);
-
- return cnt;
+ int cnt = 0;
+
+ switch (stat) {
+ case BVH_STAT_NODE_COUNT:
+ cnt = 1;
+ break;
+ case BVH_STAT_LEAF_COUNT:
+ cnt = is_leaf() ? 1 : 0;
+ break;
+ case BVH_STAT_INNER_COUNT:
+ cnt = is_leaf() ? 0 : 1;
+ break;
+ case BVH_STAT_TRIANGLE_COUNT:
+ cnt = is_leaf() ? reinterpret_cast<const LeafNode *>(this)->num_triangles() : 0;
+ break;
+ case BVH_STAT_CHILDNODE_COUNT:
+ cnt = num_children();
+ break;
+ case BVH_STAT_ALIGNED_COUNT:
+ if (!is_unaligned) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_COUNT:
+ if (is_unaligned) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_COUNT:
+ if (!is_leaf()) {
+ bool has_unaligned = false;
+ for (int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned;
+ }
+ cnt += has_unaligned ? 0 : 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_INNER_COUNT:
+ if (!is_leaf()) {
+ bool has_unaligned = false;
+ for (int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned;
+ }
+ cnt += has_unaligned ? 1 : 0;
+ }
+ break;
+ case BVH_STAT_ALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && !is_unaligned) ? 1 : 0;
+ break;
+ case BVH_STAT_UNALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && is_unaligned) ? 1 : 0;
+ break;
+ case BVH_STAT_DEPTH:
+ if (is_leaf()) {
+ cnt = 1;
+ }
+ else {
+ for (int i = 0; i < num_children(); i++) {
+ cnt = max(cnt, get_child(i)->getSubtreeSize(stat));
+ }
+ cnt += 1;
+ }
+ return cnt;
+ default:
+ assert(0); /* unknown mode */
+ }
+
+ if (!is_leaf())
+ for (int i = 0; i < num_children(); i++)
+ cnt += get_child(i)->getSubtreeSize(stat);
+
+ return cnt;
}
void BVHNode::deleteSubtree()
{
- for(int i = 0; i < num_children(); i++)
- if(get_child(i))
- get_child(i)->deleteSubtree();
+ for (int i = 0; i < num_children(); i++)
+ if (get_child(i))
+ get_child(i)->deleteSubtree();
- delete this;
+ delete this;
}
-float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) const
+float BVHNode::computeSubtreeSAHCost(const BVHParams &p, float probability) const
{
- float SAH = probability * p.cost(num_children(), num_triangles());
+ float SAH = probability * p.cost(num_children(), num_triangles());
- for(int i = 0; i < num_children(); i++) {
- BVHNode *child = get_child(i);
- SAH += child->computeSubtreeSAHCost(p, probability * child->bounds.safe_area()/bounds.safe_area());
- }
+ for (int i = 0; i < num_children(); i++) {
+ BVHNode *child = get_child(i);
+ SAH += child->computeSubtreeSAHCost(
+ p, probability * child->bounds.safe_area() / bounds.safe_area());
+ }
- return SAH;
+ return SAH;
}
uint BVHNode::update_visibility()
{
- if(!is_leaf() && visibility == 0) {
- InnerNode *inner = (InnerNode*)this;
- BVHNode *child0 = inner->children[0];
- BVHNode *child1 = inner->children[1];
+ if (!is_leaf() && visibility == 0) {
+ InnerNode *inner = (InnerNode *)this;
+ BVHNode *child0 = inner->children[0];
+ BVHNode *child1 = inner->children[1];
- visibility = child0->update_visibility()|child1->update_visibility();
- }
+ visibility = child0->update_visibility() | child1->update_visibility();
+ }
- return visibility;
+ return visibility;
}
void BVHNode::update_time()
{
- if(!is_leaf()) {
- InnerNode *inner = (InnerNode*)this;
- BVHNode *child0 = inner->children[0];
- BVHNode *child1 = inner->children[1];
- child0->update_time();
- child1->update_time();
- time_from = min(child0->time_from, child1->time_from);
- time_to = max(child0->time_to, child1->time_to);
- }
+ if (!is_leaf()) {
+ InnerNode *inner = (InnerNode *)this;
+ BVHNode *child0 = inner->children[0];
+ BVHNode *child1 = inner->children[1];
+ child0->update_time();
+ child1->update_time();
+ time_from = min(child0->time_from, child1->time_from);
+ time_to = max(child0->time_to, child1->time_to);
+ }
}
namespace {
struct DumpTraversalContext {
- /* Descriptor of wile where writing is happening. */
- FILE *stream;
- /* Unique identifier of the node current. */
- int id;
+ /* Descriptor of wile where writing is happening. */
+ FILE *stream;
+ /* Unique identifier of the node current. */
+ int id;
};
-void dump_subtree(DumpTraversalContext *context,
- const BVHNode *node,
- const BVHNode *parent = NULL)
+void dump_subtree(DumpTraversalContext *context, const BVHNode *node, const BVHNode *parent = NULL)
{
- if(node->is_leaf()) {
- fprintf(context->stream,
- " node_%p [label=\"%d\",fillcolor=\"#ccccee\",style=filled]\n",
- node,
- context->id);
- }
- else {
- fprintf(context->stream,
- " node_%p [label=\"%d\",fillcolor=\"#cceecc\",style=filled]\n",
- node,
- context->id);
- }
- if(parent != NULL) {
- fprintf(context->stream, " node_%p -> node_%p;\n", parent, node);
- }
- context->id += 1;
- for(int i = 0; i < node->num_children(); ++i) {
- dump_subtree(context, node->get_child(i), node);
- }
+ if (node->is_leaf()) {
+ fprintf(context->stream,
+ " node_%p [label=\"%d\",fillcolor=\"#ccccee\",style=filled]\n",
+ node,
+ context->id);
+ }
+ else {
+ fprintf(context->stream,
+ " node_%p [label=\"%d\",fillcolor=\"#cceecc\",style=filled]\n",
+ node,
+ context->id);
+ }
+ if (parent != NULL) {
+ fprintf(context->stream, " node_%p -> node_%p;\n", parent, node);
+ }
+ context->id += 1;
+ for (int i = 0; i < node->num_children(); ++i) {
+ dump_subtree(context, node->get_child(i), node);
+ }
}
} // namespace
void BVHNode::dump_graph(const char *filename)
{
- DumpTraversalContext context;
- context.stream = fopen(filename, "w");
- if(context.stream == NULL) {
- return;
- }
- context.id = 0;
- fprintf(context.stream, "digraph BVH {\n");
- dump_subtree(&context, this);
- fprintf(context.stream, "}\n");
- fclose(context.stream);
+ DumpTraversalContext context;
+ context.stream = fopen(filename, "w");
+ if (context.stream == NULL) {
+ return;
+ }
+ context.id = 0;
+ fprintf(context.stream, "digraph BVH {\n");
+ dump_subtree(&context, this);
+ fprintf(context.stream, "}\n");
+ fclose(context.stream);
}
/* Inner Node */
void InnerNode::print(int depth) const
{
- for(int i = 0; i < depth; i++)
- printf(" ");
+ for (int i = 0; i < depth; i++)
+ printf(" ");
- printf("inner node %p\n", (void*)this);
+ printf("inner node %p\n", (void *)this);
- if(children[0])
- children[0]->print(depth+1);
- if(children[1])
- children[1]->print(depth+1);
+ if (children[0])
+ children[0]->print(depth + 1);
+ if (children[1])
+ children[1]->print(depth + 1);
}
void LeafNode::print(int depth) const
{
- for(int i = 0; i < depth; i++)
- printf(" ");
+ for (int i = 0; i < depth; i++)
+ printf(" ");
- printf("leaf node %d to %d\n", lo, hi);
+ printf("leaf node %d to %d\n", lo, hi);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
index d9105d69739..797dd5b694e 100644
--- a/intern/cycles/bvh/bvh_node.h
+++ b/intern/cycles/bvh/bvh_node.h
@@ -24,227 +24,232 @@
CCL_NAMESPACE_BEGIN
enum BVH_STAT {
- BVH_STAT_NODE_COUNT,
- BVH_STAT_INNER_COUNT,
- BVH_STAT_LEAF_COUNT,
- BVH_STAT_TRIANGLE_COUNT,
- BVH_STAT_CHILDNODE_COUNT,
- BVH_STAT_ALIGNED_COUNT,
- BVH_STAT_UNALIGNED_COUNT,
- BVH_STAT_ALIGNED_INNER_COUNT,
- BVH_STAT_UNALIGNED_INNER_COUNT,
- BVH_STAT_ALIGNED_LEAF_COUNT,
- BVH_STAT_UNALIGNED_LEAF_COUNT,
- BVH_STAT_DEPTH,
+ BVH_STAT_NODE_COUNT,
+ BVH_STAT_INNER_COUNT,
+ BVH_STAT_LEAF_COUNT,
+ BVH_STAT_TRIANGLE_COUNT,
+ BVH_STAT_CHILDNODE_COUNT,
+ BVH_STAT_ALIGNED_COUNT,
+ BVH_STAT_UNALIGNED_COUNT,
+ BVH_STAT_ALIGNED_INNER_COUNT,
+ BVH_STAT_UNALIGNED_INNER_COUNT,
+ BVH_STAT_ALIGNED_LEAF_COUNT,
+ BVH_STAT_UNALIGNED_LEAF_COUNT,
+ BVH_STAT_DEPTH,
};
class BVHParams;
-class BVHNode
-{
-public:
- virtual ~BVHNode()
- {
- delete aligned_space;
- }
-
- virtual bool is_leaf() const = 0;
- virtual int num_children() const = 0;
- virtual BVHNode *get_child(int i) const = 0;
- virtual int num_triangles() const { return 0; }
- virtual void print(int depth = 0) const = 0;
-
- inline void set_aligned_space(const Transform& aligned_space)
- {
- is_unaligned = true;
- if(this->aligned_space == NULL) {
- this->aligned_space = new Transform(aligned_space);
- }
- else {
- *this->aligned_space = aligned_space;
- }
- }
-
- inline Transform get_aligned_space() const
- {
- if(aligned_space == NULL) {
- return transform_identity();
- }
- return *aligned_space;
- }
-
- inline bool has_unaligned() const
- {
- if(is_leaf()) {
- return false;
- }
- for(int i = 0; i < num_children(); ++i) {
- if(get_child(i)->is_unaligned) {
- return true;
- }
- }
- return false;
- }
-
- // Subtree functions
- int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const;
- float computeSubtreeSAHCost(const BVHParams& p, float probability = 1.0f) const;
- void deleteSubtree();
-
- uint update_visibility();
- void update_time();
-
- /* Dump the content of the tree as a graphviz file. */
- void dump_graph(const char *filename);
-
- // Properties.
- BoundBox bounds;
- uint visibility;
-
- bool is_unaligned;
-
- /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some
- * utilities and type defines in util_transform first.
- */
- Transform *aligned_space;
-
- float time_from, time_to;
-
-protected:
- explicit BVHNode(const BoundBox& bounds)
- : bounds(bounds),
- visibility(0),
- is_unaligned(false),
- aligned_space(NULL),
- time_from(0.0f),
- time_to(1.0f)
- {
- }
-
- explicit BVHNode(const BVHNode& other)
- : bounds(other.bounds),
- visibility(other.visibility),
- is_unaligned(other.is_unaligned),
- aligned_space(NULL),
- time_from(other.time_from),
- time_to(other.time_to)
- {
- if(other.aligned_space != NULL) {
- assert(other.is_unaligned);
- aligned_space = new Transform();
- *aligned_space = *other.aligned_space;
- }
- else {
- assert(!other.is_unaligned);
- }
- }
+class BVHNode {
+ public:
+ virtual ~BVHNode()
+ {
+ delete aligned_space;
+ }
+
+ virtual bool is_leaf() const = 0;
+ virtual int num_children() const = 0;
+ virtual BVHNode *get_child(int i) const = 0;
+ virtual int num_triangles() const
+ {
+ return 0;
+ }
+ virtual void print(int depth = 0) const = 0;
+
+ inline void set_aligned_space(const Transform &aligned_space)
+ {
+ is_unaligned = true;
+ if (this->aligned_space == NULL) {
+ this->aligned_space = new Transform(aligned_space);
+ }
+ else {
+ *this->aligned_space = aligned_space;
+ }
+ }
+
+ inline Transform get_aligned_space() const
+ {
+ if (aligned_space == NULL) {
+ return transform_identity();
+ }
+ return *aligned_space;
+ }
+
+ inline bool has_unaligned() const
+ {
+ if (is_leaf()) {
+ return false;
+ }
+ for (int i = 0; i < num_children(); ++i) {
+ if (get_child(i)->is_unaligned) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Subtree functions
+ int getSubtreeSize(BVH_STAT stat = BVH_STAT_NODE_COUNT) const;
+ float computeSubtreeSAHCost(const BVHParams &p, float probability = 1.0f) const;
+ void deleteSubtree();
+
+ uint update_visibility();
+ void update_time();
+
+ /* Dump the content of the tree as a graphviz file. */
+ void dump_graph(const char *filename);
+
+ // Properties.
+ BoundBox bounds;
+ uint visibility;
+
+ bool is_unaligned;
+
+ /* TODO(sergey): Can be stored as 3x3 matrix, but better to have some
+ * utilities and type defines in util_transform first.
+ */
+ Transform *aligned_space;
+
+ float time_from, time_to;
+
+ protected:
+ explicit BVHNode(const BoundBox &bounds)
+ : bounds(bounds),
+ visibility(0),
+ is_unaligned(false),
+ aligned_space(NULL),
+ time_from(0.0f),
+ time_to(1.0f)
+ {
+ }
+
+ explicit BVHNode(const BVHNode &other)
+ : bounds(other.bounds),
+ visibility(other.visibility),
+ is_unaligned(other.is_unaligned),
+ aligned_space(NULL),
+ time_from(other.time_from),
+ time_to(other.time_to)
+ {
+ if (other.aligned_space != NULL) {
+ assert(other.is_unaligned);
+ aligned_space = new Transform();
+ *aligned_space = *other.aligned_space;
+ }
+ else {
+ assert(!other.is_unaligned);
+ }
+ }
};
-class InnerNode : public BVHNode
-{
-public:
- static constexpr int kNumMaxChildren = 8;
-
- InnerNode(const BoundBox& bounds,
- BVHNode* child0,
- BVHNode* child1)
- : BVHNode(bounds),
- num_children_(2)
- {
- children[0] = child0;
- children[1] = child1;
- reset_unused_children();
-
- if(child0 && child1) {
- visibility = child0->visibility | child1->visibility;
- }
- else {
- /* Happens on build cancel. */
- visibility = 0;
- }
- }
-
- InnerNode(const BoundBox& bounds,
- BVHNode** children,
- const int num_children)
- : BVHNode(bounds),
- num_children_(num_children)
- {
- visibility = 0;
- time_from = FLT_MAX;
- time_to = -FLT_MAX;
- for(int i = 0; i < num_children; ++i) {
- assert(children[i] != NULL);
- visibility |= children[i]->visibility;
- this->children[i] = children[i];
- time_from = min(time_from, children[i]->time_from);
- time_to = max(time_to, children[i]->time_to);
- }
- reset_unused_children();
- }
-
- /* NOTE: This function is only used during binary BVH builder, and it
- * supposed to be configured to have 2 children which will be filled in in a
- * bit. But this is important to have children reset to NULL. */
- explicit InnerNode(const BoundBox& bounds)
- : BVHNode(bounds),
- num_children_(0)
- {
- reset_unused_children();
- visibility = 0;
- num_children_ = 2;
- }
-
- bool is_leaf() const { return false; }
- int num_children() const { return num_children_; }
- BVHNode *get_child(int i) const
- {
- assert(i >= 0 && i < num_children_);
- return children[i];
- }
- void print(int depth) const;
-
- int num_children_;
- BVHNode *children[kNumMaxChildren];
-
-protected:
- void reset_unused_children()
- {
- for(int i = num_children_; i < kNumMaxChildren; ++i) {
- children[i] = NULL;
- }
- }
+class InnerNode : public BVHNode {
+ public:
+ static constexpr int kNumMaxChildren = 8;
+
+ InnerNode(const BoundBox &bounds, BVHNode *child0, BVHNode *child1)
+ : BVHNode(bounds), num_children_(2)
+ {
+ children[0] = child0;
+ children[1] = child1;
+ reset_unused_children();
+
+ if (child0 && child1) {
+ visibility = child0->visibility | child1->visibility;
+ }
+ else {
+ /* Happens on build cancel. */
+ visibility = 0;
+ }
+ }
+
+ InnerNode(const BoundBox &bounds, BVHNode **children, const int num_children)
+ : BVHNode(bounds), num_children_(num_children)
+ {
+ visibility = 0;
+ time_from = FLT_MAX;
+ time_to = -FLT_MAX;
+ for (int i = 0; i < num_children; ++i) {
+ assert(children[i] != NULL);
+ visibility |= children[i]->visibility;
+ this->children[i] = children[i];
+ time_from = min(time_from, children[i]->time_from);
+ time_to = max(time_to, children[i]->time_to);
+ }
+ reset_unused_children();
+ }
+
+ /* NOTE: This function is only used during binary BVH builder, and it
+ * supposed to be configured to have 2 children which will be filled in in a
+ * bit. But this is important to have children reset to NULL. */
+ explicit InnerNode(const BoundBox &bounds) : BVHNode(bounds), num_children_(0)
+ {
+ reset_unused_children();
+ visibility = 0;
+ num_children_ = 2;
+ }
+
+ bool is_leaf() const
+ {
+ return false;
+ }
+ int num_children() const
+ {
+ return num_children_;
+ }
+ BVHNode *get_child(int i) const
+ {
+ assert(i >= 0 && i < num_children_);
+ return children[i];
+ }
+ void print(int depth) const;
+
+ int num_children_;
+ BVHNode *children[kNumMaxChildren];
+
+ protected:
+ void reset_unused_children()
+ {
+ for (int i = num_children_; i < kNumMaxChildren; ++i) {
+ children[i] = NULL;
+ }
+ }
};
-class LeafNode : public BVHNode
-{
-public:
- LeafNode(const BoundBox& bounds, uint visibility, int lo, int hi)
- : BVHNode(bounds),
- lo(lo),
- hi(hi)
- {
- this->bounds = bounds;
- this->visibility = visibility;
- }
-
- LeafNode(const LeafNode& other)
- : BVHNode(other),
- lo(other.lo),
- hi(other.hi)
- {
- }
-
- bool is_leaf() const { return true; }
- int num_children() const { return 0; }
- BVHNode *get_child(int) const { return NULL; }
- int num_triangles() const { return hi - lo; }
- void print(int depth) const;
-
- int lo;
- int hi;
+class LeafNode : public BVHNode {
+ public:
+ LeafNode(const BoundBox &bounds, uint visibility, int lo, int hi)
+ : BVHNode(bounds), lo(lo), hi(hi)
+ {
+ this->bounds = bounds;
+ this->visibility = visibility;
+ }
+
+ LeafNode(const LeafNode &other) : BVHNode(other), lo(other.lo), hi(other.hi)
+ {
+ }
+
+ bool is_leaf() const
+ {
+ return true;
+ }
+ int num_children() const
+ {
+ return 0;
+ }
+ BVHNode *get_child(int) const
+ {
+ return NULL;
+ }
+ int num_triangles() const
+ {
+ return hi - lo;
+ }
+ void print(int depth) const;
+
+ int lo;
+ int hi;
};
CCL_NAMESPACE_END
-#endif /* __BVH_NODE_H__ */
+#endif /* __BVH_NODE_H__ */
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index 6408d56da80..2731662a39d 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -43,120 +43,121 @@ const char *bvh_layout_name(BVHLayout layout);
/* BVH Parameters */
-class BVHParams
-{
-public:
-
- /* spatial split area threshold */
- bool use_spatial_split;
- float spatial_split_alpha;
-
- /* Unaligned nodes creation threshold */
- float unaligned_split_threshold;
-
- /* SAH costs */
- float sah_node_cost;
- float sah_primitive_cost;
-
- /* number of primitives in leaf */
- int min_leaf_size;
- int max_triangle_leaf_size;
- int max_motion_triangle_leaf_size;
- int max_curve_leaf_size;
- int max_motion_curve_leaf_size;
-
- /* object or mesh level bvh */
- bool top_level;
-
- /* BVH layout to be built. */
- BVHLayout bvh_layout;
-
- /* Mask of primitives to be included into the BVH. */
- int primitive_mask;
-
- /* Use unaligned bounding boxes.
- * Only used for curves BVH.
- */
- bool use_unaligned_nodes;
-
- /* Split time range to this number of steps and create leaf node for each
- * of this time steps.
- *
- * Speeds up rendering of motion curve primitives in the cost of higher
- * memory usage.
- */
- int num_motion_curve_steps;
-
- /* Same as above, but for triangle primitives. */
- int num_motion_triangle_steps;
-
- /* Same as in SceneParams. */
- int bvh_type;
-
- /* These are needed for Embree. */
- int curve_flags;
- int curve_subdivisions;
-
- /* fixed parameters */
- enum {
- MAX_DEPTH = 64,
- MAX_SPATIAL_DEPTH = 48,
- NUM_SPATIAL_BINS = 32
- };
-
- BVHParams()
- {
- use_spatial_split = true;
- spatial_split_alpha = 1e-5f;
-
- unaligned_split_threshold = 0.7f;
-
- /* todo: see if splitting up primitive cost to be separate for triangles
- * and curves can help. so far in tests it doesn't help, but why? */
- sah_node_cost = 1.0f;
- sah_primitive_cost = 1.0f;
-
- min_leaf_size = 1;
- max_triangle_leaf_size = 8;
- max_motion_triangle_leaf_size = 8;
- max_curve_leaf_size = 1;
- max_motion_curve_leaf_size = 4;
-
- top_level = false;
- bvh_layout = BVH_LAYOUT_BVH2;
- use_unaligned_nodes = false;
-
- primitive_mask = PRIMITIVE_ALL;
-
- num_motion_curve_steps = 0;
- num_motion_triangle_steps = 0;
-
- bvh_type = 0;
-
- curve_flags = 0;
- curve_subdivisions = 4;
- }
-
- /* SAH costs */
- __forceinline float cost(int num_nodes, int num_primitives) const
- { return node_cost(num_nodes) + primitive_cost(num_primitives); }
-
- __forceinline float primitive_cost(int n) const
- { return n*sah_primitive_cost; }
-
- __forceinline float node_cost(int n) const
- { return n*sah_node_cost; }
-
- __forceinline bool small_enough_for_leaf(int size, int level)
- { return (size <= min_leaf_size || level >= MAX_DEPTH); }
-
- /* Gets best matching BVH.
- *
- * If the requested layout is supported by the device, it will be used.
- * Otherwise, widest supported layout below that will be used.
- */
- static BVHLayout best_bvh_layout(BVHLayout requested_layout,
- BVHLayoutMask supported_layouts);
+class BVHParams {
+ public:
+ /* spatial split area threshold */
+ bool use_spatial_split;
+ float spatial_split_alpha;
+
+ /* Unaligned nodes creation threshold */
+ float unaligned_split_threshold;
+
+ /* SAH costs */
+ float sah_node_cost;
+ float sah_primitive_cost;
+
+ /* number of primitives in leaf */
+ int min_leaf_size;
+ int max_triangle_leaf_size;
+ int max_motion_triangle_leaf_size;
+ int max_curve_leaf_size;
+ int max_motion_curve_leaf_size;
+
+ /* object or mesh level bvh */
+ bool top_level;
+
+ /* BVH layout to be built. */
+ BVHLayout bvh_layout;
+
+ /* Mask of primitives to be included into the BVH. */
+ int primitive_mask;
+
+ /* Use unaligned bounding boxes.
+ * Only used for curves BVH.
+ */
+ bool use_unaligned_nodes;
+
+ /* Split time range to this number of steps and create leaf node for each
+ * of this time steps.
+ *
+ * Speeds up rendering of motion curve primitives in the cost of higher
+ * memory usage.
+ */
+ int num_motion_curve_steps;
+
+ /* Same as above, but for triangle primitives. */
+ int num_motion_triangle_steps;
+
+ /* Same as in SceneParams. */
+ int bvh_type;
+
+ /* These are needed for Embree. */
+ int curve_flags;
+ int curve_subdivisions;
+
+ /* fixed parameters */
+ enum { MAX_DEPTH = 64, MAX_SPATIAL_DEPTH = 48, NUM_SPATIAL_BINS = 32 };
+
+ BVHParams()
+ {
+ use_spatial_split = true;
+ spatial_split_alpha = 1e-5f;
+
+ unaligned_split_threshold = 0.7f;
+
+ /* todo: see if splitting up primitive cost to be separate for triangles
+ * and curves can help. so far in tests it doesn't help, but why? */
+ sah_node_cost = 1.0f;
+ sah_primitive_cost = 1.0f;
+
+ min_leaf_size = 1;
+ max_triangle_leaf_size = 8;
+ max_motion_triangle_leaf_size = 8;
+ max_curve_leaf_size = 1;
+ max_motion_curve_leaf_size = 4;
+
+ top_level = false;
+ bvh_layout = BVH_LAYOUT_BVH2;
+ use_unaligned_nodes = false;
+
+ primitive_mask = PRIMITIVE_ALL;
+
+ num_motion_curve_steps = 0;
+ num_motion_triangle_steps = 0;
+
+ bvh_type = 0;
+
+ curve_flags = 0;
+ curve_subdivisions = 4;
+ }
+
+ /* SAH costs */
+ __forceinline float cost(int num_nodes, int num_primitives) const
+ {
+ return node_cost(num_nodes) + primitive_cost(num_primitives);
+ }
+
+ __forceinline float primitive_cost(int n) const
+ {
+ return n * sah_primitive_cost;
+ }
+
+ __forceinline float node_cost(int n) const
+ {
+ return n * sah_node_cost;
+ }
+
+ __forceinline bool small_enough_for_leaf(int size, int level)
+ {
+ return (size <= min_leaf_size || level >= MAX_DEPTH);
+ }
+
+ /* Gets best matching BVH.
+ *
+ * If the requested layout is supported by the device, it will be used.
+ * Otherwise, widest supported layout below that will be used.
+ */
+ static BVHLayout best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask supported_layouts);
};
/* BVH Reference
@@ -164,49 +165,65 @@ public:
* Reference to a primitive. Primitive index and object are sneakily packed
* into BoundBox to reduce memory usage and align nicely */
-class BVHReference
-{
-public:
- __forceinline BVHReference() {}
-
- __forceinline BVHReference(const BoundBox& bounds_,
- int prim_index_,
- int prim_object_,
- int prim_type,
- float time_from = 0.0f,
- float time_to = 1.0f)
- : rbounds(bounds_),
- time_from_(time_from),
- time_to_(time_to)
- {
- rbounds.min.w = __int_as_float(prim_index_);
- rbounds.max.w = __int_as_float(prim_object_);
- type = prim_type;
- }
-
- __forceinline const BoundBox& bounds() const { return rbounds; }
- __forceinline int prim_index() const { return __float_as_int(rbounds.min.w); }
- __forceinline int prim_object() const { return __float_as_int(rbounds.max.w); }
- __forceinline int prim_type() const { return type; }
- __forceinline float time_from() const { return time_from_; }
- __forceinline float time_to() const { return time_to_; }
-
-
- BVHReference& operator=(const BVHReference &arg) {
- if(&arg != this) {
- /* TODO(sergey): Check if it is still faster to memcpy() with
- * modern compilers.
- */
- memcpy((void *)this, &arg, sizeof(BVHReference));
- }
- return *this;
- }
-
-
-protected:
- BoundBox rbounds;
- uint type;
- float time_from_, time_to_;
+class BVHReference {
+ public:
+ __forceinline BVHReference()
+ {
+ }
+
+ __forceinline BVHReference(const BoundBox &bounds_,
+ int prim_index_,
+ int prim_object_,
+ int prim_type,
+ float time_from = 0.0f,
+ float time_to = 1.0f)
+ : rbounds(bounds_), time_from_(time_from), time_to_(time_to)
+ {
+ rbounds.min.w = __int_as_float(prim_index_);
+ rbounds.max.w = __int_as_float(prim_object_);
+ type = prim_type;
+ }
+
+ __forceinline const BoundBox &bounds() const
+ {
+ return rbounds;
+ }
+ __forceinline int prim_index() const
+ {
+ return __float_as_int(rbounds.min.w);
+ }
+ __forceinline int prim_object() const
+ {
+ return __float_as_int(rbounds.max.w);
+ }
+ __forceinline int prim_type() const
+ {
+ return type;
+ }
+ __forceinline float time_from() const
+ {
+ return time_from_;
+ }
+ __forceinline float time_to() const
+ {
+ return time_to_;
+ }
+
+ BVHReference &operator=(const BVHReference &arg)
+ {
+ if (&arg != this) {
+ /* TODO(sergey): Check if it is still faster to memcpy() with
+ * modern compilers.
+ */
+ memcpy((void *)this, &arg, sizeof(BVHReference));
+ }
+ return *this;
+ }
+
+ protected:
+ BoundBox rbounds;
+ uint type;
+ float time_from_, time_to_;
};
/* BVH Range
@@ -215,53 +232,68 @@ protected:
* the reference array of a subset of primitives Again uses trickery to pack
* integers into BoundBox for alignment purposes. */
-class BVHRange
-{
-public:
- __forceinline BVHRange()
- {
- rbounds.min.w = __int_as_float(0);
- rbounds.max.w = __int_as_float(0);
- }
-
- __forceinline BVHRange(const BoundBox& bounds_, int start_, int size_)
- : rbounds(bounds_)
- {
- rbounds.min.w = __int_as_float(start_);
- rbounds.max.w = __int_as_float(size_);
- }
-
- __forceinline BVHRange(const BoundBox& bounds_, const BoundBox& cbounds_, int start_, int size_)
- : rbounds(bounds_), cbounds(cbounds_)
- {
- rbounds.min.w = __int_as_float(start_);
- rbounds.max.w = __int_as_float(size_);
- }
-
- __forceinline void set_start(int start_) { rbounds.min.w = __int_as_float(start_); }
-
- __forceinline const BoundBox& bounds() const { return rbounds; }
- __forceinline const BoundBox& cent_bounds() const { return cbounds; }
- __forceinline int start() const { return __float_as_int(rbounds.min.w); }
- __forceinline int size() const { return __float_as_int(rbounds.max.w); }
- __forceinline int end() const { return start() + size(); }
-
-protected:
- BoundBox rbounds;
- BoundBox cbounds;
+class BVHRange {
+ public:
+ __forceinline BVHRange()
+ {
+ rbounds.min.w = __int_as_float(0);
+ rbounds.max.w = __int_as_float(0);
+ }
+
+ __forceinline BVHRange(const BoundBox &bounds_, int start_, int size_) : rbounds(bounds_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ rbounds.max.w = __int_as_float(size_);
+ }
+
+ __forceinline BVHRange(const BoundBox &bounds_, const BoundBox &cbounds_, int start_, int size_)
+ : rbounds(bounds_), cbounds(cbounds_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ rbounds.max.w = __int_as_float(size_);
+ }
+
+ __forceinline void set_start(int start_)
+ {
+ rbounds.min.w = __int_as_float(start_);
+ }
+
+ __forceinline const BoundBox &bounds() const
+ {
+ return rbounds;
+ }
+ __forceinline const BoundBox &cent_bounds() const
+ {
+ return cbounds;
+ }
+ __forceinline int start() const
+ {
+ return __float_as_int(rbounds.min.w);
+ }
+ __forceinline int size() const
+ {
+ return __float_as_int(rbounds.max.w);
+ }
+ __forceinline int end() const
+ {
+ return start() + size();
+ }
+
+ protected:
+ BoundBox rbounds;
+ BoundBox cbounds;
};
/* BVH Spatial Bin */
-struct BVHSpatialBin
-{
- BoundBox bounds;
- int enter;
- int exit;
+struct BVHSpatialBin {
+ BoundBox bounds;
+ int enter;
+ int exit;
- __forceinline BVHSpatialBin()
- {
- }
+ __forceinline BVHSpatialBin()
+ {
+ }
};
/* BVH Spatial Storage
@@ -272,18 +304,18 @@ struct BVHSpatialBin
*/
struct BVHSpatialStorage {
- /* Accumulated bounds when sweeping from right to left. */
- vector<BoundBox> right_bounds;
+ /* Accumulated bounds when sweeping from right to left. */
+ vector<BoundBox> right_bounds;
- /* Bins used for histogram when selecting best split plane. */
- BVHSpatialBin bins[3][BVHParams::NUM_SPATIAL_BINS];
+ /* Bins used for histogram when selecting best split plane. */
+ BVHSpatialBin bins[3][BVHParams::NUM_SPATIAL_BINS];
- /* Temporary storage for the new references. Used by spatial split to store
- * new references in before they're getting inserted into actual array,
- */
- vector<BVHReference> new_references;
+ /* Temporary storage for the new references. Used by spatial split to store
+ * new references in before they're getting inserted into actual array,
+ */
+ vector<BVHReference> new_references;
};
CCL_NAMESPACE_END
-#endif /* __BVH_PARAMS_H__ */
+#endif /* __BVH_PARAMS_H__ */
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
index f4f73ab2f2f..4498a759c08 100644
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ b/intern/cycles/bvh/bvh_sort.cpp
@@ -27,79 +27,77 @@ CCL_NAMESPACE_BEGIN
static const int BVH_SORT_THRESHOLD = 4096;
struct BVHReferenceCompare {
-public:
- int dim;
- const BVHUnaligned *unaligned_heuristic;
- const Transform *aligned_space;
-
- BVHReferenceCompare(int dim,
- const BVHUnaligned *unaligned_heuristic,
- const Transform *aligned_space)
- : dim(dim),
- unaligned_heuristic(unaligned_heuristic),
- aligned_space(aligned_space)
- {
- }
-
- __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
- {
- return (aligned_space != NULL)
- ? unaligned_heuristic->compute_aligned_prim_boundbox(
- prim, *aligned_space)
- : prim.bounds();
- }
-
- /* Compare two references.
- *
- * Returns value is similar to return value of strcmp().
- */
- __forceinline int compare(const BVHReference& ra,
- const BVHReference& rb) const
- {
- BoundBox ra_bounds = get_prim_bounds(ra),
- rb_bounds = get_prim_bounds(rb);
- float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
- float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
-
- if(ca < cb) return -1;
- else if(ca > cb) return 1;
- else if(ra.prim_object() < rb.prim_object()) return -1;
- else if(ra.prim_object() > rb.prim_object()) return 1;
- else if(ra.prim_index() < rb.prim_index()) return -1;
- else if(ra.prim_index() > rb.prim_index()) return 1;
- else if(ra.prim_type() < rb.prim_type()) return -1;
- else if(ra.prim_type() > rb.prim_type()) return 1;
-
- return 0;
- }
-
- bool operator()(const BVHReference& ra, const BVHReference& rb)
- {
- return (compare(ra, rb) < 0);
- }
+ public:
+ int dim;
+ const BVHUnaligned *unaligned_heuristic;
+ const Transform *aligned_space;
+
+ BVHReferenceCompare(int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : dim(dim), unaligned_heuristic(unaligned_heuristic), aligned_space(aligned_space)
+ {
+ }
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ return (aligned_space != NULL) ?
+ unaligned_heuristic->compute_aligned_prim_boundbox(prim, *aligned_space) :
+ prim.bounds();
+ }
+
+ /* Compare two references.
+ *
+ * Returns value is similar to return value of strcmp().
+ */
+ __forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
+ {
+ BoundBox ra_bounds = get_prim_bounds(ra), rb_bounds = get_prim_bounds(rb);
+ float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
+ float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
+
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ else if (ra.prim_object() < rb.prim_object())
+ return -1;
+ else if (ra.prim_object() > rb.prim_object())
+ return 1;
+ else if (ra.prim_index() < rb.prim_index())
+ return -1;
+ else if (ra.prim_index() > rb.prim_index())
+ return 1;
+ else if (ra.prim_type() < rb.prim_type())
+ return -1;
+ else if (ra.prim_type() > rb.prim_type())
+ return 1;
+
+ return 0;
+ }
+
+ bool operator()(const BVHReference &ra, const BVHReference &rb)
+ {
+ return (compare(ra, rb) < 0);
+ }
};
static void bvh_reference_sort_threaded(TaskPool *task_pool,
BVHReference *data,
const int job_start,
const int job_end,
- const BVHReferenceCompare& compare);
+ const BVHReferenceCompare &compare);
class BVHSortTask : public Task {
-public:
- BVHSortTask(TaskPool *task_pool,
- BVHReference *data,
- const int job_start,
- const int job_end,
- const BVHReferenceCompare& compare)
- {
- run = function_bind(bvh_reference_sort_threaded,
- task_pool,
- data,
- job_start,
- job_end,
- compare);
- }
+ public:
+ BVHSortTask(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare &compare)
+ {
+ run = function_bind(bvh_reference_sort_threaded, task_pool, data, job_start, job_end, compare);
+ }
};
/* Multi-threaded reference sort. */
@@ -107,74 +105,71 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool,
BVHReference *data,
const int job_start,
const int job_end,
- const BVHReferenceCompare& compare)
+ const BVHReferenceCompare &compare)
{
- int start = job_start, end = job_end;
- bool have_work = (start < end);
- while(have_work) {
- const int count = job_end - job_start;
- if(count < BVH_SORT_THRESHOLD) {
- /* Number of reference low enough, faster to finish the job
- * in one thread rather than to spawn more threads.
- */
- sort(data+job_start, data+job_end+1, compare);
- break;
- }
- /* Single QSort step.
- * Use median-of-three method for the pivot point.
- */
- int left = start, right = end;
- int center = (left + right) >> 1;
- if(compare.compare(data[left], data[center]) > 0) {
- swap(data[left], data[center]);
- }
- if(compare.compare(data[left], data[right]) > 0) {
- swap(data[left], data[right]);
- }
- if(compare.compare(data[center], data[right]) > 0) {
- swap(data[center], data[right]);
- }
- swap(data[center], data[right - 1]);
- BVHReference median = data[right - 1];
- do {
- while(compare.compare(data[left], median) < 0) {
- ++left;
- }
- while(compare.compare(data[right], median) > 0) {
- --right;
- }
- if(left <= right) {
- swap(data[left], data[right]);
- ++left;
- --right;
- }
- } while(left <= right);
- /* We only create one new task here to reduce downside effects of
- * latency in TaskScheduler.
- * So generally current thread keeps working on the left part of the
- * array, and we create new task for the right side.
- * However, if there's nothing to be done in the left side of the array
- * we don't create any tasks and make it so current thread works on the
- * right side.
- */
- have_work = false;
- if(left < end) {
- if(start < right) {
- task_pool->push(new BVHSortTask(task_pool,
- data,
- left, end,
- compare), true);
- }
- else {
- start = left;
- have_work = true;
- }
- }
- if(start < right) {
- end = right;
- have_work = true;
- }
- }
+ int start = job_start, end = job_end;
+ bool have_work = (start < end);
+ while (have_work) {
+ const int count = job_end - job_start;
+ if (count < BVH_SORT_THRESHOLD) {
+ /* Number of reference low enough, faster to finish the job
+ * in one thread rather than to spawn more threads.
+ */
+ sort(data + job_start, data + job_end + 1, compare);
+ break;
+ }
+ /* Single QSort step.
+ * Use median-of-three method for the pivot point.
+ */
+ int left = start, right = end;
+ int center = (left + right) >> 1;
+ if (compare.compare(data[left], data[center]) > 0) {
+ swap(data[left], data[center]);
+ }
+ if (compare.compare(data[left], data[right]) > 0) {
+ swap(data[left], data[right]);
+ }
+ if (compare.compare(data[center], data[right]) > 0) {
+ swap(data[center], data[right]);
+ }
+ swap(data[center], data[right - 1]);
+ BVHReference median = data[right - 1];
+ do {
+ while (compare.compare(data[left], median) < 0) {
+ ++left;
+ }
+ while (compare.compare(data[right], median) > 0) {
+ --right;
+ }
+ if (left <= right) {
+ swap(data[left], data[right]);
+ ++left;
+ --right;
+ }
+ } while (left <= right);
+ /* We only create one new task here to reduce downside effects of
+ * latency in TaskScheduler.
+ * So generally current thread keeps working on the left part of the
+ * array, and we create new task for the right side.
+ * However, if there's nothing to be done in the left side of the array
+ * we don't create any tasks and make it so current thread works on the
+ * right side.
+ */
+ have_work = false;
+ if (left < end) {
+ if (start < right) {
+ task_pool->push(new BVHSortTask(task_pool, data, left, end, compare), true);
+ }
+ else {
+ start = left;
+ have_work = true;
+ }
+ }
+ if (start < right) {
+ end = right;
+ have_work = true;
+ }
+ }
}
void bvh_reference_sort(int start,
@@ -184,20 +179,20 @@ void bvh_reference_sort(int start,
const BVHUnaligned *unaligned_heuristic,
const Transform *aligned_space)
{
- const int count = end - start;
- BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
- if(count < BVH_SORT_THRESHOLD) {
- /* It is important to not use any mutex if array is small enough,
- * otherwise we end up in situation when we're going to sleep far
- * too often.
- */
- sort(data+start, data+end, compare);
- }
- else {
- TaskPool task_pool;
- bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
- task_pool.wait_work();
- }
+ const int count = end - start;
+ BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
+ if (count < BVH_SORT_THRESHOLD) {
+ /* It is important to not use any mutex if array is small enough,
+ * otherwise we end up in situation when we're going to sleep far
+ * too often.
+ */
+ sort(data + start, data + end, compare);
+ }
+ else {
+ TaskPool task_pool;
+ bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
+ task_pool.wait_work();
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h
index 6910cc1e9b4..936401d8607 100644
--- a/intern/cycles/bvh/bvh_sort.h
+++ b/intern/cycles/bvh/bvh_sort.h
@@ -35,4 +35,4 @@ void bvh_reference_sort(int start,
CCL_NAMESPACE_END
-#endif /* __BVH_SORT_H__ */
+#endif /* __BVH_SORT_H__ */
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index c55ba40b565..bd261c10d55 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -31,322 +31,314 @@ CCL_NAMESPACE_BEGIN
BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BVHSpatialStorage *storage,
- const BVHRange& range,
+ const BVHRange &range,
vector<BVHReference> *references,
float nodeSAH,
const BVHUnaligned *unaligned_heuristic,
const Transform *aligned_space)
-: sah(FLT_MAX),
- dim(0),
- num_left(0),
- left_bounds(BoundBox::empty),
- right_bounds(BoundBox::empty),
- storage_(storage),
- references_(references),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
+ : sah(FLT_MAX),
+ dim(0),
+ num_left(0),
+ left_bounds(BoundBox::empty),
+ right_bounds(BoundBox::empty),
+ storage_(storage),
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
- const BVHReference *ref_ptr = &references_->at(range.start());
- float min_sah = FLT_MAX;
-
- storage_->right_bounds.resize(range.size());
-
- for(int dim = 0; dim < 3; dim++) {
- /* Sort references. */
- bvh_reference_sort(range.start(),
- range.end(),
- &references_->at(0),
- dim,
- unaligned_heuristic_,
- aligned_space_);
-
- /* sweep right to left and determine bounds. */
- BoundBox right_bounds = BoundBox::empty;
- for(int i = range.size() - 1; i > 0; i--) {
- BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
- right_bounds.grow(prim_bounds);
- storage_->right_bounds[i - 1] = right_bounds;
- }
-
- /* sweep left to right and select lowest SAH. */
- BoundBox left_bounds = BoundBox::empty;
-
- for(int i = 1; i < range.size(); i++) {
- BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
- left_bounds.grow(prim_bounds);
- right_bounds = storage_->right_bounds[i - 1];
-
- float sah = nodeSAH +
- left_bounds.safe_area() * builder->params.primitive_cost(i) +
- right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
-
- if(sah < min_sah) {
- min_sah = sah;
-
- this->sah = sah;
- this->dim = dim;
- this->num_left = i;
- this->left_bounds = left_bounds;
- this->right_bounds = right_bounds;
- }
- }
- }
+ const BVHReference *ref_ptr = &references_->at(range.start());
+ float min_sah = FLT_MAX;
+
+ storage_->right_bounds.resize(range.size());
+
+ for (int dim = 0; dim < 3; dim++) {
+ /* Sort references. */
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ /* sweep right to left and determine bounds. */
+ BoundBox right_bounds = BoundBox::empty;
+ for (int i = range.size() - 1; i > 0; i--) {
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
+ right_bounds.grow(prim_bounds);
+ storage_->right_bounds[i - 1] = right_bounds;
+ }
+
+ /* sweep left to right and select lowest SAH. */
+ BoundBox left_bounds = BoundBox::empty;
+
+ for (int i = 1; i < range.size(); i++) {
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
+ left_bounds.grow(prim_bounds);
+ right_bounds = storage_->right_bounds[i - 1];
+
+ float sah = nodeSAH + left_bounds.safe_area() * builder->params.primitive_cost(i) +
+ right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
+
+ if (sah < min_sah) {
+ min_sah = sah;
+
+ this->sah = sah;
+ this->dim = dim;
+ this->num_left = i;
+ this->left_bounds = left_bounds;
+ this->right_bounds = right_bounds;
+ }
+ }
+ }
}
-void BVHObjectSplit::split(BVHRange& left,
- BVHRange& right,
- const BVHRange& range)
+void BVHObjectSplit::split(BVHRange &left, BVHRange &right, const BVHRange &range)
{
- assert(references_->size() > 0);
- /* sort references according to split */
- bvh_reference_sort(range.start(),
- range.end(),
- &references_->at(0),
- this->dim,
- unaligned_heuristic_,
- aligned_space_);
-
- BoundBox effective_left_bounds, effective_right_bounds;
- const int num_right = range.size() - this->num_left;
- if(aligned_space_ == NULL) {
- effective_left_bounds = left_bounds;
- effective_right_bounds = right_bounds;
- }
- else {
- effective_left_bounds = BoundBox::empty;
- effective_right_bounds = BoundBox::empty;
- for(int i = 0; i < this->num_left; ++i) {
- BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
- effective_left_bounds.grow(prim_boundbox);
- }
- for(int i = 0; i < num_right; ++i) {
- BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
- effective_right_bounds.grow(prim_boundbox);
- }
- }
-
- /* split node ranges */
- left = BVHRange(effective_left_bounds, range.start(), this->num_left);
- right = BVHRange(effective_right_bounds, left.end(), num_right);
+ assert(references_->size() > 0);
+ /* sort references according to split */
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ this->dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ BoundBox effective_left_bounds, effective_right_bounds;
+ const int num_right = range.size() - this->num_left;
+ if (aligned_space_ == NULL) {
+ effective_left_bounds = left_bounds;
+ effective_right_bounds = right_bounds;
+ }
+ else {
+ effective_left_bounds = BoundBox::empty;
+ effective_right_bounds = BoundBox::empty;
+ for (int i = 0; i < this->num_left; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
+ effective_left_bounds.grow(prim_boundbox);
+ }
+ for (int i = 0; i < num_right; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
+ effective_right_bounds.grow(prim_boundbox);
+ }
+ }
+
+ /* split node ranges */
+ left = BVHRange(effective_left_bounds, range.start(), this->num_left);
+ right = BVHRange(effective_right_bounds, left.end(), num_right);
}
/* Spatial Split */
-BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
+BVHSpatialSplit::BVHSpatialSplit(const BVHBuild &builder,
BVHSpatialStorage *storage,
- const BVHRange& range,
+ const BVHRange &range,
vector<BVHReference> *references,
float nodeSAH,
const BVHUnaligned *unaligned_heuristic,
const Transform *aligned_space)
-: sah(FLT_MAX),
- dim(0),
- pos(0.0f),
- storage_(storage),
- references_(references),
- unaligned_heuristic_(unaligned_heuristic),
- aligned_space_(aligned_space)
+ : sah(FLT_MAX),
+ dim(0),
+ pos(0.0f),
+ storage_(storage),
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
- /* initialize bins. */
- BoundBox range_bounds;
- if(aligned_space == NULL) {
- range_bounds = range.bounds();
- }
- else {
- range_bounds = unaligned_heuristic->compute_aligned_boundbox(
- range,
- &references->at(0),
- *aligned_space);
- }
-
- float3 origin = range_bounds.min;
- float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
- float3 invBinSize = 1.0f / binSize;
-
- for(int dim = 0; dim < 3; dim++) {
- for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- BVHSpatialBin& bin = storage_->bins[dim][i];
-
- bin.bounds = BoundBox::empty;
- bin.enter = 0;
- bin.exit = 0;
- }
- }
-
- /* chop references into bins. */
- for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
- const BVHReference& ref = references_->at(refIdx);
- BoundBox prim_bounds = get_prim_bounds(ref);
- float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
- float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
- int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
- int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
-
- firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
- lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
-
- for(int dim = 0; dim < 3; dim++) {
- BVHReference currRef(get_prim_bounds(ref),
- ref.prim_index(),
- ref.prim_object(),
- ref.prim_type());
-
- for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
- BVHReference leftRef, rightRef;
-
- split_reference(builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
- storage_->bins[dim][i].bounds.grow(leftRef.bounds());
- currRef = rightRef;
- }
-
- storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
- storage_->bins[dim][firstBin[dim]].enter++;
- storage_->bins[dim][lastBin[dim]].exit++;
- }
- }
-
- /* select best split plane. */
- storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
- for(int dim = 0; dim < 3; dim++) {
- /* sweep right to left and determine bounds. */
- BoundBox right_bounds = BoundBox::empty;
- for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
- right_bounds.grow(storage_->bins[dim][i].bounds);
- storage_->right_bounds[i - 1] = right_bounds;
- }
-
- /* sweep left to right and select lowest SAH. */
- BoundBox left_bounds = BoundBox::empty;
- int leftNum = 0;
- int rightNum = range.size();
-
- for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- left_bounds.grow(storage_->bins[dim][i - 1].bounds);
- leftNum += storage_->bins[dim][i - 1].enter;
- rightNum -= storage_->bins[dim][i - 1].exit;
-
- float sah = nodeSAH +
- left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
- storage_->right_bounds[i - 1].safe_area() * builder.params.primitive_cost(rightNum);
-
- if(sah < this->sah) {
- this->sah = sah;
- this->dim = dim;
- this->pos = origin[dim] + binSize[dim] * (float)i;
- }
- }
- }
+ /* initialize bins. */
+ BoundBox range_bounds;
+ if (aligned_space == NULL) {
+ range_bounds = range.bounds();
+ }
+ else {
+ range_bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range, &references->at(0), *aligned_space);
+ }
+
+ float3 origin = range_bounds.min;
+ float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
+ float3 invBinSize = 1.0f / binSize;
+
+ for (int dim = 0; dim < 3; dim++) {
+ for (int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+ BVHSpatialBin &bin = storage_->bins[dim][i];
+
+ bin.bounds = BoundBox::empty;
+ bin.enter = 0;
+ bin.exit = 0;
+ }
+ }
+
+ /* chop references into bins. */
+ for (unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
+ const BVHReference &ref = references_->at(refIdx);
+ BoundBox prim_bounds = get_prim_bounds(ref);
+ float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
+ float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
+ int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
+ int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
+
+ firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
+ lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
+
+ for (int dim = 0; dim < 3; dim++) {
+ BVHReference currRef(
+ get_prim_bounds(ref), ref.prim_index(), ref.prim_object(), ref.prim_type());
+
+ for (int i = firstBin[dim]; i < lastBin[dim]; i++) {
+ BVHReference leftRef, rightRef;
+
+ split_reference(
+ builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
+ storage_->bins[dim][i].bounds.grow(leftRef.bounds());
+ currRef = rightRef;
+ }
+
+ storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
+ storage_->bins[dim][firstBin[dim]].enter++;
+ storage_->bins[dim][lastBin[dim]].exit++;
+ }
+ }
+
+ /* select best split plane. */
+ storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
+ for (int dim = 0; dim < 3; dim++) {
+ /* sweep right to left and determine bounds. */
+ BoundBox right_bounds = BoundBox::empty;
+ for (int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
+ right_bounds.grow(storage_->bins[dim][i].bounds);
+ storage_->right_bounds[i - 1] = right_bounds;
+ }
+
+ /* sweep left to right and select lowest SAH. */
+ BoundBox left_bounds = BoundBox::empty;
+ int leftNum = 0;
+ int rightNum = range.size();
+
+ for (int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+ left_bounds.grow(storage_->bins[dim][i - 1].bounds);
+ leftNum += storage_->bins[dim][i - 1].enter;
+ rightNum -= storage_->bins[dim][i - 1].exit;
+
+ float sah = nodeSAH + left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
+ storage_->right_bounds[i - 1].safe_area() *
+ builder.params.primitive_cost(rightNum);
+
+ if (sah < this->sah) {
+ this->sah = sah;
+ this->dim = dim;
+ this->pos = origin[dim] + binSize[dim] * (float)i;
+ }
+ }
+ }
}
void BVHSpatialSplit::split(BVHBuild *builder,
- BVHRange& left,
- BVHRange& right,
- const BVHRange& range)
+ BVHRange &left,
+ BVHRange &right,
+ const BVHRange &range)
{
- /* Categorize references and compute bounds.
- *
- * Left-hand side: [left_start, left_end[
- * Uncategorized/split: [left_end, right_start[
- * Right-hand side: [right_start, refs.size()[ */
-
- vector<BVHReference>& refs = *references_;
- int left_start = range.start();
- int left_end = left_start;
- int right_start = range.end();
- int right_end = range.end();
- BoundBox left_bounds = BoundBox::empty;
- BoundBox right_bounds = BoundBox::empty;
-
- for(int i = left_end; i < right_start; i++) {
- BoundBox prim_bounds = get_prim_bounds(refs[i]);
- if(prim_bounds.max[this->dim] <= this->pos) {
- /* entirely on the left-hand side */
- left_bounds.grow(prim_bounds);
- swap(refs[i], refs[left_end++]);
- }
- else if(prim_bounds.min[this->dim] >= this->pos) {
- /* entirely on the right-hand side */
- right_bounds.grow(prim_bounds);
- swap(refs[i--], refs[--right_start]);
- }
- }
-
- /* Duplicate or unsplit references intersecting both sides.
- *
- * Duplication happens into a temporary pre-allocated vector in order to
- * reduce number of memmove() calls happening in vector.insert().
- */
- vector<BVHReference>& new_refs = storage_->new_references;
- new_refs.clear();
- new_refs.reserve(right_start - left_end);
- while(left_end < right_start) {
- /* split reference. */
- BVHReference curr_ref(get_prim_bounds(refs[left_end]),
- refs[left_end].prim_index(),
- refs[left_end].prim_object(),
- refs[left_end].prim_type());
- BVHReference lref, rref;
- split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
-
- /* compute SAH for duplicate/unsplit candidates. */
- BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
- BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
- BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
- BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
-
- lub.grow(curr_ref.bounds());
- rub.grow(curr_ref.bounds());
- ldb.grow(lref.bounds());
- rdb.grow(rref.bounds());
-
- float lac = builder->params.primitive_cost(left_end - left_start);
- float rac = builder->params.primitive_cost(right_end - right_start);
- float lbc = builder->params.primitive_cost(left_end - left_start + 1);
- float rbc = builder->params.primitive_cost(right_end - right_start + 1);
-
- float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
- float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
- float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
- float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
-
- if(minSAH == unsplitLeftSAH) {
- /* unsplit to left */
- left_bounds = lub;
- left_end++;
- }
- else if(minSAH == unsplitRightSAH) {
- /* unsplit to right */
- right_bounds = rub;
- swap(refs[left_end], refs[--right_start]);
- }
- else {
- /* duplicate */
- left_bounds = ldb;
- right_bounds = rdb;
- refs[left_end++] = lref;
- new_refs.push_back(rref);
- right_end++;
- }
- }
- /* Insert duplicated references into actual array in one go. */
- if(new_refs.size() != 0) {
- refs.insert(refs.begin() + (right_end - new_refs.size()),
- new_refs.begin(),
- new_refs.end());
- }
- if(aligned_space_ != NULL) {
- left_bounds = right_bounds = BoundBox::empty;
- for(int i = left_start; i < left_end - left_start; ++i) {
- BoundBox prim_boundbox = references_->at(i).bounds();
- left_bounds.grow(prim_boundbox);
- }
- for(int i = right_start; i < right_end - right_start; ++i) {
- BoundBox prim_boundbox = references_->at(i).bounds();
- right_bounds.grow(prim_boundbox);
- }
- }
- left = BVHRange(left_bounds, left_start, left_end - left_start);
- right = BVHRange(right_bounds, right_start, right_end - right_start);
+ /* Categorize references and compute bounds.
+ *
+ * Left-hand side: [left_start, left_end[
+ * Uncategorized/split: [left_end, right_start[
+ * Right-hand side: [right_start, refs.size()[ */
+
+ vector<BVHReference> &refs = *references_;
+ int left_start = range.start();
+ int left_end = left_start;
+ int right_start = range.end();
+ int right_end = range.end();
+ BoundBox left_bounds = BoundBox::empty;
+ BoundBox right_bounds = BoundBox::empty;
+
+ for (int i = left_end; i < right_start; i++) {
+ BoundBox prim_bounds = get_prim_bounds(refs[i]);
+ if (prim_bounds.max[this->dim] <= this->pos) {
+ /* entirely on the left-hand side */
+ left_bounds.grow(prim_bounds);
+ swap(refs[i], refs[left_end++]);
+ }
+ else if (prim_bounds.min[this->dim] >= this->pos) {
+ /* entirely on the right-hand side */
+ right_bounds.grow(prim_bounds);
+ swap(refs[i--], refs[--right_start]);
+ }
+ }
+
+ /* Duplicate or unsplit references intersecting both sides.
+ *
+ * Duplication happens into a temporary pre-allocated vector in order to
+ * reduce number of memmove() calls happening in vector.insert().
+ */
+ vector<BVHReference> &new_refs = storage_->new_references;
+ new_refs.clear();
+ new_refs.reserve(right_start - left_end);
+ while (left_end < right_start) {
+ /* split reference. */
+ BVHReference curr_ref(get_prim_bounds(refs[left_end]),
+ refs[left_end].prim_index(),
+ refs[left_end].prim_object(),
+ refs[left_end].prim_type());
+ BVHReference lref, rref;
+ split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
+
+ /* compute SAH for duplicate/unsplit candidates. */
+ BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
+ BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
+ BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
+ BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
+
+ lub.grow(curr_ref.bounds());
+ rub.grow(curr_ref.bounds());
+ ldb.grow(lref.bounds());
+ rdb.grow(rref.bounds());
+
+ float lac = builder->params.primitive_cost(left_end - left_start);
+ float rac = builder->params.primitive_cost(right_end - right_start);
+ float lbc = builder->params.primitive_cost(left_end - left_start + 1);
+ float rbc = builder->params.primitive_cost(right_end - right_start + 1);
+
+ float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
+ float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
+ float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
+ float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
+
+ if (minSAH == unsplitLeftSAH) {
+ /* unsplit to left */
+ left_bounds = lub;
+ left_end++;
+ }
+ else if (minSAH == unsplitRightSAH) {
+ /* unsplit to right */
+ right_bounds = rub;
+ swap(refs[left_end], refs[--right_start]);
+ }
+ else {
+ /* duplicate */
+ left_bounds = ldb;
+ right_bounds = rdb;
+ refs[left_end++] = lref;
+ new_refs.push_back(rref);
+ right_end++;
+ }
+ }
+ /* Insert duplicated references into actual array in one go. */
+ if (new_refs.size() != 0) {
+ refs.insert(refs.begin() + (right_end - new_refs.size()), new_refs.begin(), new_refs.end());
+ }
+ if (aligned_space_ != NULL) {
+ left_bounds = right_bounds = BoundBox::empty;
+ for (int i = left_start; i < left_end - left_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ left_bounds.grow(prim_boundbox);
+ }
+ for (int i = right_start; i < right_end - right_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ right_bounds.grow(prim_boundbox);
+ }
+ }
+ left = BVHRange(left_bounds, left_start, left_end - left_start);
+ right = BVHRange(right_bounds, right_start, right_end - right_start);
}
void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
@@ -354,36 +346,36 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
int prim_index,
int dim,
float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds)
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
{
- Mesh::Triangle t = mesh->get_triangle(prim_index);
- const float3 *verts = &mesh->verts[0];
- float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
- v1 = get_unaligned_point(v1);
-
- for(int i = 0; i < 3; i++) {
- float3 v0 = v1;
- int vindex = t.v[i];
- v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
- v1 = get_unaligned_point(v1);
- float v0p = v0[dim];
- float v1p = v1[dim];
-
- /* insert vertex to the boxes it belongs to. */
- if(v0p <= pos)
- left_bounds.grow(v0);
-
- if(v0p >= pos)
- right_bounds.grow(v0);
-
- /* edge intersects the plane => insert intersection to both boxes. */
- if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
- float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
- left_bounds.grow(t);
- right_bounds.grow(t);
- }
- }
+ Mesh::Triangle t = mesh->get_triangle(prim_index);
+ const float3 *verts = &mesh->verts[0];
+ float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
+ v1 = get_unaligned_point(v1);
+
+ for (int i = 0; i < 3; i++) {
+ float3 v0 = v1;
+ int vindex = t.v[i];
+ v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
+ v1 = get_unaligned_point(v1);
+ float v0p = v0[dim];
+ float v1p = v1[dim];
+
+ /* insert vertex to the boxes it belongs to. */
+ if (v0p <= pos)
+ left_bounds.grow(v0);
+
+ if (v0p >= pos)
+ right_bounds.grow(v0);
+
+ /* edge intersects the plane => insert intersection to both boxes. */
+ if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+ float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+ left_bounds.grow(t);
+ right_bounds.grow(t);
+ }
+ }
}
void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh,
@@ -392,163 +384,125 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh,
int segment_index,
int dim,
float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds)
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
{
- /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
- Mesh::Curve curve = mesh->get_curve(prim_index);
- const int k0 = curve.first_key + segment_index;
- const int k1 = k0 + 1;
- float3 v0 = mesh->curve_keys[k0];
- float3 v1 = mesh->curve_keys[k1];
-
- if(tfm != NULL) {
- v0 = transform_point(tfm, v0);
- v1 = transform_point(tfm, v1);
- }
- v0 = get_unaligned_point(v0);
- v1 = get_unaligned_point(v1);
-
- float v0p = v0[dim];
- float v1p = v1[dim];
-
- /* insert vertex to the boxes it belongs to. */
- if(v0p <= pos)
- left_bounds.grow(v0);
-
- if(v0p >= pos)
- right_bounds.grow(v0);
-
- if(v1p <= pos)
- left_bounds.grow(v1);
-
- if(v1p >= pos)
- right_bounds.grow(v1);
-
- /* edge intersects the plane => insert intersection to both boxes. */
- if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
- float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
- left_bounds.grow(t);
- right_bounds.grow(t);
- }
+ /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
+ Mesh::Curve curve = mesh->get_curve(prim_index);
+ const int k0 = curve.first_key + segment_index;
+ const int k1 = k0 + 1;
+ float3 v0 = mesh->curve_keys[k0];
+ float3 v1 = mesh->curve_keys[k1];
+
+ if (tfm != NULL) {
+ v0 = transform_point(tfm, v0);
+ v1 = transform_point(tfm, v1);
+ }
+ v0 = get_unaligned_point(v0);
+ v1 = get_unaligned_point(v1);
+
+ float v0p = v0[dim];
+ float v1p = v1[dim];
+
+ /* insert vertex to the boxes it belongs to. */
+ if (v0p <= pos)
+ left_bounds.grow(v0);
+
+ if (v0p >= pos)
+ right_bounds.grow(v0);
+
+ if (v1p <= pos)
+ left_bounds.grow(v1);
+
+ if (v1p >= pos)
+ right_bounds.grow(v1);
+
+ /* edge intersects the plane => insert intersection to both boxes. */
+ if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+ float3 t = lerp(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+ left_bounds.grow(t);
+ right_bounds.grow(t);
+ }
}
-void BVHSpatialSplit::split_triangle_reference(const BVHReference& ref,
+void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref,
const Mesh *mesh,
int dim,
float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds)
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
{
- split_triangle_primitive(mesh,
- NULL,
- ref.prim_index(),
- dim,
- pos,
- left_bounds,
- right_bounds);
+ split_triangle_primitive(mesh, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
}
-void BVHSpatialSplit::split_curve_reference(const BVHReference& ref,
+void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
const Mesh *mesh,
int dim,
float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds)
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
{
- split_curve_primitive(mesh,
- NULL,
- ref.prim_index(),
- PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()),
- dim,
- pos,
- left_bounds,
- right_bounds);
+ split_curve_primitive(mesh,
+ NULL,
+ ref.prim_index(),
+ PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()),
+ dim,
+ pos,
+ left_bounds,
+ right_bounds);
}
-void BVHSpatialSplit::split_object_reference(const Object *object,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds)
+void BVHSpatialSplit::split_object_reference(
+ const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
{
- Mesh *mesh = object->mesh;
- for(int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
- split_triangle_primitive(mesh,
- &object->tfm,
- tri_idx,
- dim,
- pos,
- left_bounds,
- right_bounds);
- }
- for(int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) {
- Mesh::Curve curve = mesh->get_curve(curve_idx);
- for(int segment_idx = 0;
- segment_idx < curve.num_keys - 1;
- ++segment_idx)
- {
- split_curve_primitive(mesh,
- &object->tfm,
- curve_idx,
- segment_idx,
- dim,
- pos,
- left_bounds,
- right_bounds);
- }
- }
+ Mesh *mesh = object->mesh;
+ for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
+ split_triangle_primitive(mesh, &object->tfm, tri_idx, dim, pos, left_bounds, right_bounds);
+ }
+ for (int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) {
+ Mesh::Curve curve = mesh->get_curve(curve_idx);
+ for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
+ split_curve_primitive(
+ mesh, &object->tfm, curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
+ }
+ }
}
-void BVHSpatialSplit::split_reference(const BVHBuild& builder,
- BVHReference& left,
- BVHReference& right,
- const BVHReference& ref,
+void BVHSpatialSplit::split_reference(const BVHBuild &builder,
+ BVHReference &left,
+ BVHReference &right,
+ const BVHReference &ref,
int dim,
float pos)
{
- /* initialize boundboxes */
- BoundBox left_bounds = BoundBox::empty;
- BoundBox right_bounds = BoundBox::empty;
-
- /* loop over vertices/edges. */
- const Object *ob = builder.objects[ref.prim_object()];
- const Mesh *mesh = ob->mesh;
-
- if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
- split_triangle_reference(ref,
- mesh,
- dim,
- pos,
- left_bounds,
- right_bounds);
- }
- else if(ref.prim_type() & PRIMITIVE_ALL_CURVE) {
- split_curve_reference(ref,
- mesh,
- dim,
- pos,
- left_bounds,
- right_bounds);
- }
- else {
- split_object_reference(ob,
- dim,
- pos,
- left_bounds,
- right_bounds);
- }
-
- /* intersect with original bounds. */
- left_bounds.max[dim] = pos;
- right_bounds.min[dim] = pos;
-
- left_bounds.intersect(ref.bounds());
- right_bounds.intersect(ref.bounds());
-
- /* set references */
- left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
- right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
+ /* initialize boundboxes */
+ BoundBox left_bounds = BoundBox::empty;
+ BoundBox right_bounds = BoundBox::empty;
+
+ /* loop over vertices/edges. */
+ const Object *ob = builder.objects[ref.prim_object()];
+ const Mesh *mesh = ob->mesh;
+
+ if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
+ split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
+ }
+ else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ split_curve_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
+ }
+ else {
+ split_object_reference(ob, dim, pos, left_bounds, right_bounds);
+ }
+
+ /* intersect with original bounds. */
+ left_bounds.max[dim] = pos;
+ right_bounds.min[dim] = pos;
+
+ left_bounds.intersect(ref.bounds());
+ right_bounds.intersect(ref.bounds());
+
+ /* set references */
+ left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
+ right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
index cb47deab211..eddd1c27f49 100644
--- a/intern/cycles/bvh/bvh_split.h
+++ b/intern/cycles/bvh/bvh_split.h
@@ -28,235 +28,211 @@ struct Transform;
/* Object Split */
-class BVHObjectSplit
-{
-public:
- float sah;
- int dim;
- int num_left;
- BoundBox left_bounds;
- BoundBox right_bounds;
-
- BVHObjectSplit() {}
- BVHObjectSplit(BVHBuild *builder,
- BVHSpatialStorage *storage,
- const BVHRange& range,
- vector<BVHReference> *references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHRange& left,
- BVHRange& right,
- const BVHRange& range);
-
-protected:
- BVHSpatialStorage *storage_;
- vector<BVHReference> *references_;
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
- {
- if(aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(
- prim, *aligned_space_);
- }
- }
+class BVHObjectSplit {
+ public:
+ float sah;
+ int dim;
+ int num_left;
+ BoundBox left_bounds;
+ BoundBox right_bounds;
+
+ BVHObjectSplit()
+ {
+ }
+ BVHObjectSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> *references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHRange &left, BVHRange &right, const BVHRange &range);
+
+ protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
};
/* Spatial Split */
-class BVHSpatialSplit
-{
-public:
- float sah;
- int dim;
- float pos;
-
- BVHSpatialSplit() : sah(FLT_MAX),
- dim(0),
- pos(0.0f),
- storage_(NULL),
- references_(NULL) {}
- BVHSpatialSplit(const BVHBuild& builder,
- BVHSpatialStorage *storage,
- const BVHRange& range,
- vector<BVHReference> *references,
- float nodeSAH,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL);
-
- void split(BVHBuild *builder,
- BVHRange& left,
- BVHRange& right,
- const BVHRange& range);
-
- void split_reference(const BVHBuild& builder,
- BVHReference& left,
- BVHReference& right,
- const BVHReference& ref,
- int dim,
- float pos);
-
-protected:
- BVHSpatialStorage *storage_;
- vector<BVHReference> *references_;
- const BVHUnaligned *unaligned_heuristic_;
- const Transform *aligned_space_;
-
- /* Lower-level functions which calculates boundaries of left and right nodes
- * needed for spatial split.
- *
- * Operates directly with primitive specified by it's index, reused by higher
- * level splitting functions.
- */
- void split_triangle_primitive(const Mesh *mesh,
- const Transform *tfm,
- int prim_index,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds);
- void split_curve_primitive(const Mesh *mesh,
- const Transform *tfm,
- int prim_index,
- int segment_index,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds);
-
- /* Lower-level functions which calculates boundaries of left and right nodes
- * needed for spatial split.
- *
- * Operates with BVHReference, internally uses lower level API functions.
- */
- void split_triangle_reference(const BVHReference& ref,
- const Mesh *mesh,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds);
- void split_curve_reference(const BVHReference& ref,
- const Mesh *mesh,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds);
- void split_object_reference(const Object *object,
- int dim,
- float pos,
- BoundBox& left_bounds,
- BoundBox& right_bounds);
-
- __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
- {
- if(aligned_space_ == NULL) {
- return prim.bounds();
- }
- else {
- return unaligned_heuristic_->compute_aligned_prim_boundbox(
- prim, *aligned_space_);
- }
- }
-
- __forceinline float3 get_unaligned_point(const float3& point) const
- {
- if(aligned_space_ == NULL) {
- return point;
- }
- else {
- return transform_point(aligned_space_, point);
- }
- }
+class BVHSpatialSplit {
+ public:
+ float sah;
+ int dim;
+ float pos;
+
+ BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f), storage_(NULL), references_(NULL)
+ {
+ }
+ BVHSpatialSplit(const BVHBuild &builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> *references,
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
+
+ void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range);
+
+ void split_reference(const BVHBuild &builder,
+ BVHReference &left,
+ BVHReference &right,
+ const BVHReference &ref,
+ int dim,
+ float pos);
+
+ protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ /* Lower-level functions which calculates boundaries of left and right nodes
+ * needed for spatial split.
+ *
+ * Operates directly with primitive specified by it's index, reused by higher
+ * level splitting functions.
+ */
+ void split_triangle_primitive(const Mesh *mesh,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_curve_primitive(const Mesh *mesh,
+ const Transform *tfm,
+ int prim_index,
+ int segment_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+
+ /* Lower-level functions which calculates boundaries of left and right nodes
+ * needed for spatial split.
+ *
+ * Operates with BVHReference, internally uses lower level API functions.
+ */
+ void split_triangle_reference(const BVHReference &ref,
+ const Mesh *mesh,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_curve_reference(const BVHReference &ref,
+ const Mesh *mesh,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds);
+ void split_object_reference(
+ const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds);
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
+ {
+ if (aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(prim, *aligned_space_);
+ }
+ }
+
+ __forceinline float3 get_unaligned_point(const float3 &point) const
+ {
+ if (aligned_space_ == NULL) {
+ return point;
+ }
+ else {
+ return transform_point(aligned_space_, point);
+ }
+ }
};
/* Mixed Object-Spatial Split */
-class BVHMixedSplit
-{
-public:
- BVHObjectSplit object;
- BVHSpatialSplit spatial;
-
- float leafSAH;
- float nodeSAH;
- float minSAH;
-
- bool no_split;
-
- BoundBox bounds;
-
- BVHMixedSplit() {}
-
- __forceinline BVHMixedSplit(BVHBuild *builder,
- BVHSpatialStorage *storage,
- const BVHRange& range,
- vector<BVHReference> *references,
- int level,
- const BVHUnaligned *unaligned_heuristic = NULL,
- const Transform *aligned_space = NULL)
- {
- if(aligned_space == NULL) {
- bounds = range.bounds();
- }
- else {
- bounds = unaligned_heuristic->compute_aligned_boundbox(
- range,
- &references->at(0),
- *aligned_space);
- }
- /* find split candidates. */
- float area = bounds.safe_area();
-
- leafSAH = area * builder->params.primitive_cost(range.size());
- nodeSAH = area * builder->params.node_cost(2);
-
- object = BVHObjectSplit(builder,
- storage,
- range,
- references,
- nodeSAH,
- unaligned_heuristic,
- aligned_space);
-
- if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
- BoundBox overlap = object.left_bounds;
- overlap.intersect(object.right_bounds);
-
- if(overlap.safe_area() >= builder->spatial_min_overlap) {
- spatial = BVHSpatialSplit(*builder,
- storage,
- range,
- references,
- nodeSAH,
- unaligned_heuristic,
- aligned_space);
- }
- }
-
- /* leaf SAH is the lowest => create leaf. */
- minSAH = min(min(leafSAH, object.sah), spatial.sah);
- no_split = (minSAH == leafSAH &&
- builder->range_within_max_leaf_size(range, *references));
- }
-
- __forceinline void split(BVHBuild *builder,
- BVHRange& left,
- BVHRange& right,
- const BVHRange& range)
- {
- if(builder->params.use_spatial_split && minSAH == spatial.sah)
- spatial.split(builder, left, right, range);
- if(!left.size() || !right.size())
- object.split(left, right, range);
- }
+class BVHMixedSplit {
+ public:
+ BVHObjectSplit object;
+ BVHSpatialSplit spatial;
+
+ float leafSAH;
+ float nodeSAH;
+ float minSAH;
+
+ bool no_split;
+
+ BoundBox bounds;
+
+ BVHMixedSplit()
+ {
+ }
+
+ __forceinline BVHMixedSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange &range,
+ vector<BVHReference> *references,
+ int level,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL)
+ {
+ if (aligned_space == NULL) {
+ bounds = range.bounds();
+ }
+ else {
+ bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range, &references->at(0), *aligned_space);
+ }
+ /* find split candidates. */
+ float area = bounds.safe_area();
+
+ leafSAH = area * builder->params.primitive_cost(range.size());
+ nodeSAH = area * builder->params.node_cost(2);
+
+ object = BVHObjectSplit(
+ builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
+
+ if (builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
+ BoundBox overlap = object.left_bounds;
+ overlap.intersect(object.right_bounds);
+
+ if (overlap.safe_area() >= builder->spatial_min_overlap) {
+ spatial = BVHSpatialSplit(
+ *builder, storage, range, references, nodeSAH, unaligned_heuristic, aligned_space);
+ }
+ }
+
+ /* leaf SAH is the lowest => create leaf. */
+ minSAH = min(min(leafSAH, object.sah), spatial.sah);
+ no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range, *references));
+ }
+
+ __forceinline void split(BVHBuild *builder,
+ BVHRange &left,
+ BVHRange &right,
+ const BVHRange &range)
+ {
+ if (builder->params.use_spatial_split && minSAH == spatial.sah)
+ spatial.split(builder, left, right, range);
+ if (!left.size() || !right.size())
+ object.split(left, right, range);
+ }
};
CCL_NAMESPACE_END
-#endif /* __BVH_SPLIT_H__ */
+#endif /* __BVH_SPLIT_H__ */
diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp
index 910f82137c5..1843ca403a5 100644
--- a/intern/cycles/bvh/bvh_unaligned.cpp
+++ b/intern/cycles/bvh/bvh_unaligned.cpp
@@ -27,150 +27,137 @@
CCL_NAMESPACE_BEGIN
-
-BVHUnaligned::BVHUnaligned(const vector<Object*>& objects)
- : objects_(objects)
+BVHUnaligned::BVHUnaligned(const vector<Object *> &objects) : objects_(objects)
{
}
-Transform BVHUnaligned::compute_aligned_space(
- const BVHObjectBinning& range,
- const BVHReference *references) const
+Transform BVHUnaligned::compute_aligned_space(const BVHObjectBinning &range,
+ const BVHReference *references) const
{
- for(int i = range.start(); i < range.end(); ++i) {
- const BVHReference& ref = references[i];
- Transform aligned_space;
- /* Use first primitive which defines correct direction to define
- * the orientation space.
- */
- if(compute_aligned_space(ref, &aligned_space)) {
- return aligned_space;
- }
- }
- return transform_identity();
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if (compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
}
-Transform BVHUnaligned::compute_aligned_space(
- const BVHRange& range,
- const BVHReference *references) const
+Transform BVHUnaligned::compute_aligned_space(const BVHRange &range,
+ const BVHReference *references) const
{
- for(int i = range.start(); i < range.end(); ++i) {
- const BVHReference& ref = references[i];
- Transform aligned_space;
- /* Use first primitive which defines correct direction to define
- * the orientation space.
- */
- if(compute_aligned_space(ref, &aligned_space)) {
- return aligned_space;
- }
- }
- return transform_identity();
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if (compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
}
-bool BVHUnaligned::compute_aligned_space(const BVHReference& ref,
- Transform *aligned_space) const
+bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const
{
- const Object *object = objects_[ref.prim_object()];
- const int packed_type = ref.prim_type();
- const int type = (packed_type & PRIMITIVE_ALL);
- if(type & PRIMITIVE_CURVE) {
- const int curve_index = ref.prim_index();
- const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
- const Mesh *mesh = object->mesh;
- const Mesh::Curve& curve = mesh->get_curve(curve_index);
- const int key = curve.first_key + segment;
- const float3 v1 = mesh->curve_keys[key],
- v2 = mesh->curve_keys[key + 1];
- float length;
- const float3 axis = normalize_len(v2 - v1, &length);
- if(length > 1e-6f) {
- *aligned_space = make_transform_frame(axis);
- return true;
- }
- }
- *aligned_space = transform_identity();
- return false;
+ const Object *object = objects_[ref.prim_object()];
+ const int packed_type = ref.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if (type & PRIMITIVE_CURVE) {
+ const int curve_index = ref.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve &curve = mesh->get_curve(curve_index);
+ const int key = curve.first_key + segment;
+ const float3 v1 = mesh->curve_keys[key], v2 = mesh->curve_keys[key + 1];
+ float length;
+ const float3 axis = normalize_len(v2 - v1, &length);
+ if (length > 1e-6f) {
+ *aligned_space = make_transform_frame(axis);
+ return true;
+ }
+ }
+ *aligned_space = transform_identity();
+ return false;
}
-BoundBox BVHUnaligned::compute_aligned_prim_boundbox(
- const BVHReference& prim,
- const Transform& aligned_space) const
+BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
+ const Transform &aligned_space) const
{
- BoundBox bounds = BoundBox::empty;
- const Object *object = objects_[prim.prim_object()];
- const int packed_type = prim.prim_type();
- const int type = (packed_type & PRIMITIVE_ALL);
- if(type & PRIMITIVE_CURVE) {
- const int curve_index = prim.prim_index();
- const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
- const Mesh *mesh = object->mesh;
- const Mesh::Curve& curve = mesh->get_curve(curve_index);
- curve.bounds_grow(segment,
- &mesh->curve_keys[0],
- &mesh->curve_radius[0],
- aligned_space,
- bounds);
- }
- else {
- bounds = prim.bounds().transformed(&aligned_space);
- }
- return bounds;
+ BoundBox bounds = BoundBox::empty;
+ const Object *object = objects_[prim.prim_object()];
+ const int packed_type = prim.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if (type & PRIMITIVE_CURVE) {
+ const int curve_index = prim.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve &curve = mesh->get_curve(curve_index);
+ curve.bounds_grow(
+ segment, &mesh->curve_keys[0], &mesh->curve_radius[0], aligned_space, bounds);
+ }
+ else {
+ bounds = prim.bounds().transformed(&aligned_space);
+ }
+ return bounds;
}
-BoundBox BVHUnaligned::compute_aligned_boundbox(
- const BVHObjectBinning& range,
- const BVHReference *references,
- const Transform& aligned_space,
- BoundBox *cent_bounds) const
+BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHObjectBinning &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds) const
{
- BoundBox bounds = BoundBox::empty;
- if(cent_bounds != NULL) {
- *cent_bounds = BoundBox::empty;
- }
- for(int i = range.start(); i < range.end(); ++i) {
- const BVHReference& ref = references[i];
- BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
- bounds.grow(ref_bounds);
- if(cent_bounds != NULL) {
- cent_bounds->grow(ref_bounds.center2());
- }
- }
- return bounds;
+ BoundBox bounds = BoundBox::empty;
+ if (cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if (cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
}
-BoundBox BVHUnaligned::compute_aligned_boundbox(
- const BVHRange& range,
- const BVHReference *references,
- const Transform& aligned_space,
- BoundBox *cent_bounds) const
+BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHRange &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds) const
{
- BoundBox bounds = BoundBox::empty;
- if(cent_bounds != NULL) {
- *cent_bounds = BoundBox::empty;
- }
- for(int i = range.start(); i < range.end(); ++i) {
- const BVHReference& ref = references[i];
- BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
- bounds.grow(ref_bounds);
- if(cent_bounds != NULL) {
- cent_bounds->grow(ref_bounds.center2());
- }
- }
- return bounds;
+ BoundBox bounds = BoundBox::empty;
+ if (cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for (int i = range.start(); i < range.end(); ++i) {
+ const BVHReference &ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if (cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
}
-Transform BVHUnaligned::compute_node_transform(
- const BoundBox& bounds,
- const Transform& aligned_space)
+Transform BVHUnaligned::compute_node_transform(const BoundBox &bounds,
+ const Transform &aligned_space)
{
- Transform space = aligned_space;
- space.x.w -= bounds.min.x;
- space.y.w -= bounds.min.y;
- space.z.w -= bounds.min.z;
- float3 dim = bounds.max - bounds.min;
- return transform_scale(1.0f / max(1e-18f, dim.x),
- 1.0f / max(1e-18f, dim.y),
- 1.0f / max(1e-18f, dim.z)) * space;
+ Transform space = aligned_space;
+ space.x.w -= bounds.min.x;
+ space.y.w -= bounds.min.y;
+ space.z.w -= bounds.min.z;
+ float3 dim = bounds.max - bounds.min;
+ return transform_scale(
+ 1.0f / max(1e-18f, dim.x), 1.0f / max(1e-18f, dim.y), 1.0f / max(1e-18f, dim.z)) *
+ space;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h
index bcfb6ed68da..e8a9a25daa8 100644
--- a/intern/cycles/bvh/bvh_unaligned.h
+++ b/intern/cycles/bvh/bvh_unaligned.h
@@ -30,51 +30,44 @@ class Object;
/* Helper class to perform calculations needed for unaligned nodes. */
class BVHUnaligned {
-public:
- BVHUnaligned(const vector<Object*>& objects);
+ public:
+ BVHUnaligned(const vector<Object *> &objects);
- /* Calculate alignment for the oriented node for a given range. */
- Transform compute_aligned_space(
- const BVHObjectBinning& range,
- const BVHReference *references) const;
- Transform compute_aligned_space(
- const BVHRange& range,
- const BVHReference *references) const;
+ /* Calculate alignment for the oriented node for a given range. */
+ Transform compute_aligned_space(const BVHObjectBinning &range,
+ const BVHReference *references) const;
+ Transform compute_aligned_space(const BVHRange &range, const BVHReference *references) const;
- /* Calculate alignment for the oriented node for a given reference.
- *
- * Return true when space was calculated successfully.
- */
- bool compute_aligned_space(const BVHReference& ref,
- Transform *aligned_space) const;
+ /* Calculate alignment for the oriented node for a given reference.
+ *
+ * Return true when space was calculated successfully.
+ */
+ bool compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const;
- /* Calculate primitive's bounding box in given space. */
- BoundBox compute_aligned_prim_boundbox(
- const BVHReference& prim,
- const Transform& aligned_space) const;
+ /* Calculate primitive's bounding box in given space. */
+ BoundBox compute_aligned_prim_boundbox(const BVHReference &prim,
+ const Transform &aligned_space) const;
- /* Calculate bounding box in given space. */
- BoundBox compute_aligned_boundbox(
- const BVHObjectBinning& range,
- const BVHReference *references,
- const Transform& aligned_space,
- BoundBox *cent_bounds = NULL) const;
- BoundBox compute_aligned_boundbox(
- const BVHRange& range,
- const BVHReference *references,
- const Transform& aligned_space,
- BoundBox *cent_bounds = NULL) const;
+ /* Calculate bounding box in given space. */
+ BoundBox compute_aligned_boundbox(const BVHObjectBinning &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+ BoundBox compute_aligned_boundbox(const BVHRange &range,
+ const BVHReference *references,
+ const Transform &aligned_space,
+ BoundBox *cent_bounds = NULL) const;
- /* Calculate affine transform for node packing.
- * Bounds will be in the range of 0..1.
- */
- static Transform compute_node_transform(const BoundBox& bounds,
- const Transform& aligned_space);
-protected:
- /* List of objects BVH is being created for. */
- const vector<Object*>& objects_;
+ /* Calculate affine transform for node packing.
+ * Bounds will be in the range of 0..1.
+ */
+ static Transform compute_node_transform(const BoundBox &bounds, const Transform &aligned_space);
+
+ protected:
+ /* List of objects BVH is being created for. */
+ const vector<Object *> &objects_;
};
CCL_NAMESPACE_END
-#endif /* __BVH_UNALIGNED_H__ */
+#endif /* __BVH_UNALIGNED_H__ */