2 * Adapted from code copyright 2009-2010 NVIDIA Corporation
3 * Modifications Copyright 2011, Blender Foundation.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
23 #include "bvh_build.h"
25 #include "bvh_params.h"
27 #include "util_cache.h"
28 #include "util_debug.h"
29 #include "util_foreach.h"
31 #include "util_progress.h"
32 #include "util_types.h"
43 BVHStackEntry(const BVHNode* n = 0, int i = 0)
50 return (node->is_leaf())? ~idx: idx;
56 BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
57 : params(params_), objects(objects_)
61 BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
64 return new QBVH(params, objects);
66 return new RegularBVH(params, objects);
71 bool BVH::cache_read(CacheData& key)
73 key.add(¶ms, sizeof(params));
75 foreach(Object *ob, objects) {
76 key.add(ob->mesh->verts);
77 key.add(ob->mesh->triangles);
82 if(Cache::global.lookup(key, value)) {
83 value.read(pack.root_index);
85 value.read(pack.nodes);
86 value.read(pack.object_node);
87 value.read(pack.tri_woop);
88 value.read(pack.prim_visibility);
89 value.read(pack.prim_index);
90 value.read(pack.prim_object);
91 value.read(pack.is_leaf);
99 void BVH::cache_write(CacheData& key)
103 value.add(pack.root_index);
105 value.add(pack.nodes);
106 value.add(pack.object_node);
107 value.add(pack.tri_woop);
108 value.add(pack.prim_visibility);
109 value.add(pack.prim_index);
110 value.add(pack.prim_object);
111 value.add(pack.is_leaf);
113 Cache::global.insert(key, value);
118 void BVH::build(Progress& progress)
120 progress.set_substatus("Building BVH");
123 CacheData key("bvh");
125 if(params.use_cache) {
126 progress.set_substatus("Looking in BVH cache");
133 vector<int> prim_index;
134 vector<int> prim_object;
136 BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
137 BVHNode *root = bvh_build.run();
139 if(progress.get_cancel()) {
140 if(root) root->deleteSubtree();
144 /* todo: get rid of this copy */
145 pack.prim_index = prim_index;
146 pack.prim_object = prim_object;
149 if(!params.top_level)
150 pack.SAH = root->computeSubtreeSAHCost(params);
152 if(progress.get_cancel()) {
153 root->deleteSubtree();
158 progress.set_substatus("Packing BVH triangles");
161 if(progress.get_cancel()) {
162 root->deleteSubtree();
167 progress.set_substatus("Packing BVH nodes");
168 array<int> tmp_prim_object = pack.prim_object;
169 pack_nodes(tmp_prim_object, root);
171 /* free build nodes */
172 root->deleteSubtree();
174 if(progress.get_cancel()) return;
177 if(params.use_cache) {
178 progress.set_substatus("Writing BVH cache");
185 void BVH::refit(Progress& progress)
187 progress.set_substatus("Packing BVH triangles");
190 if(progress.get_cancel()) return;
192 progress.set_substatus("Refitting BVH nodes");
198 void BVH::pack_triangle(int idx, float4 woop[3])
200 /* create Woop triangle */
201 int tob = pack.prim_object[idx];
202 const Mesh *mesh = objects[tob]->mesh;
203 int tidx = pack.prim_index[idx];
204 const int *vidx = mesh->triangles[tidx].v;
205 const float3* vpos = &mesh->verts[0];
206 float3 v0 = vpos[vidx[0]];
207 float3 v1 = vpos[vidx[1]];
208 float3 v2 = vpos[vidx[2]];
212 float3 r2 = cross(r0, r1);
214 if(dot(r0, r0) == 0.0f || dot(r1, r1) == 0.0f || dot(r2, r2) == 0.0f) {
216 woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
217 woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
218 woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
221 Transform t = make_transform(
222 r0.x, r1.x, r2.x, v2.x,
223 r0.y, r1.y, r2.y, v2.y,
224 r0.z, r1.z, r2.z, v2.z,
225 0.0f, 0.0f, 0.0f, 1.0f);
227 t = transform_inverse(t);
229 woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w);
230 woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w);
231 woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w);
235 void BVH::pack_triangles()
237 int nsize = TRI_NODE_SIZE;
238 size_t tidx_size = pack.prim_index.size();
240 pack.tri_woop.clear();
241 pack.tri_woop.resize(tidx_size * nsize);
242 pack.prim_visibility.clear();
243 pack.prim_visibility.resize(tidx_size);
245 for(unsigned int i = 0; i < tidx_size; i++) {
246 if(pack.prim_index[i] != -1) {
249 pack_triangle(i, woop);
250 memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
252 int tob = pack.prim_object[i];
253 Object *ob = objects[tob];
254 pack.prim_visibility[i] = ob->visibility;
261 void BVH::pack_instances(size_t nodes_size)
263 /* The BVH's for instances are built separately, but for traversal all
264 BVH's are stored in global arrays. This function merges them into the
265 top level BVH, adjusting indexes and offsets where appropriate. */
266 bool use_qbvh = params.use_qbvh;
267 size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
269 /* adjust primitive index to point to the triangle in the global array, for
270 meshes with transform applied and already in the top level BVH */
271 for(size_t i = 0; i < pack.prim_index.size(); i++)
272 if(pack.prim_index[i] != -1)
273 pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
275 /* track offsets of instanced BVH data in global array */
276 size_t tri_offset = pack.prim_index.size();
277 size_t nodes_offset = nodes_size;
279 /* clear array that gives the node indexes for instanced objects */
280 pack.object_node.clear();
283 size_t prim_index_size = pack.prim_index.size();
284 size_t tri_woop_size = pack.tri_woop.size();
286 size_t pack_prim_index_offset = prim_index_size;
287 size_t pack_tri_woop_offset = tri_woop_size;
288 size_t pack_nodes_offset = nodes_size;
289 size_t object_offset = 0;
291 map<Mesh*, int> mesh_map;
293 foreach(Object *ob, objects) {
294 Mesh *mesh = ob->mesh;
295 BVH *bvh = mesh->bvh;
297 if(!mesh->transform_applied) {
298 if(mesh_map.find(mesh) == mesh_map.end()) {
299 prim_index_size += bvh->pack.prim_index.size();
300 tri_woop_size += bvh->pack.tri_woop.size();
301 nodes_size += bvh->pack.nodes.size()*nsize;
310 pack.prim_index.resize(prim_index_size);
311 pack.prim_object.resize(prim_index_size);
312 pack.prim_visibility.resize(prim_index_size);
313 pack.tri_woop.resize(tri_woop_size);
314 pack.nodes.resize(nodes_size);
315 pack.object_node.resize(objects.size());
317 int *pack_prim_index = &pack.prim_index[0];
318 int *pack_prim_object = &pack.prim_object[0];
319 uint *pack_prim_visibility = &pack.prim_visibility[0];
320 float4 *pack_tri_woop = &pack.tri_woop[0];
321 int4 *pack_nodes = &pack.nodes[0];
324 foreach(Object *ob, objects) {
325 Mesh *mesh = ob->mesh;
327 /* if mesh transform is applied, that means it's already in the top
328 level BVH, and we don't need to merge it in */
329 if(mesh->transform_applied) {
330 pack.object_node[object_offset++] = 0;
334 /* if mesh already added once, don't add it again, but used set
335 node offset for this object */
336 map<Mesh*, int>::iterator it = mesh_map.find(mesh);
338 if(mesh_map.find(mesh) != mesh_map.end()) {
339 int noffset = it->second;
340 pack.object_node[object_offset++] = noffset;
344 BVH *bvh = mesh->bvh;
346 int noffset = nodes_offset/nsize;
347 int mesh_tri_offset = mesh->tri_offset;
349 /* fill in node indexes for instances */
350 if(bvh->pack.is_leaf[0])
351 pack.object_node[object_offset++] = -noffset-1;
353 pack.object_node[object_offset++] = noffset;
355 mesh_map[mesh] = pack.object_node[object_offset-1];
357 /* merge primitive and object indexes */
359 size_t bvh_prim_index_size = bvh->pack.prim_index.size();
360 int *bvh_prim_index = &bvh->pack.prim_index[0];
361 uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
363 for(size_t i = 0; i < bvh_prim_index_size; i++) {
364 pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
365 pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
366 pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
367 pack_prim_index_offset++;
371 /* merge triangle intersection data */
373 memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
374 bvh->pack.tri_woop.size()*sizeof(float4));
375 pack_tri_woop_offset += bvh->pack.tri_woop.size();
380 size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1;
381 int4 *bvh_nodes = &bvh->pack.nodes[0];
382 size_t bvh_nodes_size = bvh->pack.nodes.size();
383 int *bvh_is_leaf = &bvh->pack.is_leaf[0];
385 for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
386 memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
388 /* modify offsets into arrays */
389 int4 data = bvh_nodes[i + nsize_bbox];
392 data.x += tri_offset;
393 data.y += tri_offset;
396 data.x += (data.x < 0)? -noffset: noffset;
397 data.y += (data.y < 0)? -noffset: noffset;
400 data.z += (data.z < 0)? -noffset: noffset;
401 data.w += (data.w < 0)? -noffset: noffset;
405 pack_nodes[pack_nodes_offset + nsize_bbox] = data;
408 pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1];
410 pack_nodes_offset += nsize;
414 nodes_offset += bvh->pack.nodes.size();
415 tri_offset += bvh->pack.prim_index.size();
421 RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
422 : BVH(params_, objects_)
426 void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
428 if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
430 pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, leaf->m_visibility, leaf->m_visibility);
433 pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility);
436 void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
438 pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
441 void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
443 int4 data[BVH_NODE_SIZE] =
445 make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)),
446 make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)),
447 make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)),
448 make_int4(c0, c1, visibility0, visibility1)
451 memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
454 void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
456 size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
460 pack.is_leaf.clear();
461 pack.is_leaf.resize(node_size);
463 /* for top level BVH, first merge existing BVH's so we know the offsets */
465 pack_instances(node_size*BVH_NODE_SIZE);
467 pack.nodes.resize(node_size*BVH_NODE_SIZE);
471 vector<BVHStackEntry> stack;
472 stack.push_back(BVHStackEntry(root, nextNodeIdx++));
474 while(stack.size()) {
475 BVHStackEntry e = stack.back();
478 pack.is_leaf[e.idx] = e.node->is_leaf();
480 if(e.node->is_leaf()) {
482 const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
487 stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
488 stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
490 pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
494 /* root index to start traversal at, to handle case of single leaf node */
495 pack.root_index = (pack.is_leaf[0])? -1: 0;
498 void RegularBVH::refit_nodes()
500 assert(!params.top_level);
504 refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
507 void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
509 int4 *data = &pack.nodes[idx*4];
515 /* refit leaf node */
516 for(int tri = c0; tri < c1; tri++) {
517 int tidx = pack.prim_index[tri];
518 int tob = pack.prim_object[tri];
519 Object *ob = objects[tob];
522 /* object instance */
523 bbox.grow(ob->bounds);
527 const Mesh *mesh = ob->mesh;
528 int tri_offset = (params.top_level)? mesh->tri_offset: 0;
529 const int *vidx = mesh->triangles[tidx - tri_offset].v;
530 const float3 *vpos = &mesh->verts[0];
532 bbox.grow(vpos[vidx[0]]);
533 bbox.grow(vpos[vidx[1]]);
534 bbox.grow(vpos[vidx[2]]);
537 visibility |= ob->visibility;
540 pack_node(idx, bbox, bbox, c0, c1, visibility, visibility);
543 /* refit inner node, set bbox from children */
544 BoundBox bbox0, bbox1;
545 uint visibility0 = 0, visibility1 = 0;
547 refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
548 refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
550 pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
554 visibility = visibility0|visibility1;
560 QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
561 : BVH(params_, objects_)
563 params.use_qbvh = true;
565 /* todo: use visibility */
568 void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
570 float4 data[BVH_QNODE_SIZE];
572 memset(data, 0, sizeof(data));
574 if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
576 data[6].x = __int_as_float(~(leaf->m_lo));
577 data[6].y = __int_as_float(0);
581 data[6].x = __int_as_float(leaf->m_lo);
582 data[6].y = __int_as_float(leaf->m_hi);
585 memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
588 void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
590 float4 data[BVH_QNODE_SIZE];
592 for(int i = 0; i < num; i++) {
593 float3 bb_min = en[i].node->m_bounds.min;
594 float3 bb_max = en[i].node->m_bounds.max;
596 data[0][i] = bb_min.x;
597 data[1][i] = bb_max.x;
598 data[2][i] = bb_min.y;
599 data[3][i] = bb_max.y;
600 data[4][i] = bb_min.z;
601 data[5][i] = bb_max.z;
603 data[6][i] = __int_as_float(en[i].encodeIdx());
607 for(int i = num; i < 4; i++) {
616 data[6][i] = __int_as_float(0);
620 memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
623 /* Quad SIMD Nodes */
625 void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
627 size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
631 pack.is_leaf.clear();
632 pack.is_leaf.resize(node_size);
634 /* for top level BVH, first merge existing BVH's so we know the offsets */
636 pack_instances(node_size*BVH_QNODE_SIZE);
638 pack.nodes.resize(node_size*BVH_QNODE_SIZE);
642 vector<BVHStackEntry> stack;
643 stack.push_back(BVHStackEntry(root, nextNodeIdx++));
645 while(stack.size()) {
646 BVHStackEntry e = stack.back();
649 pack.is_leaf[e.idx] = e.node->is_leaf();
651 if(e.node->is_leaf()) {
653 const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
658 const BVHNode *node = e.node;
659 const BVHNode *node0 = node->get_child(0);
660 const BVHNode *node1 = node->get_child(1);
663 const BVHNode *nodes[4];
666 if(node0->is_leaf()) {
667 nodes[numnodes++] = node0;
670 nodes[numnodes++] = node0->get_child(0);
671 nodes[numnodes++] = node0->get_child(1);
674 if(node1->is_leaf()) {
675 nodes[numnodes++] = node1;
678 nodes[numnodes++] = node1->get_child(0);
679 nodes[numnodes++] = node1->get_child(1);
682 /* push entries on the stack */
683 for(int i = 0; i < numnodes; i++)
684 stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
687 pack_inner(e, &stack[stack.size()-numnodes], numnodes);
691 /* root index to start traversal at, to handle case of single leaf node */
692 pack.root_index = (pack.is_leaf[0])? -1: 0;
695 void QBVH::refit_nodes()
697 assert(0); /* todo */