Blender V2.61 - r43446

bvh.cpp

Go to the documentation of this file.
00001 /*
00002  * Adapted from code copyright 2009-2010 NVIDIA Corporation
00003  * Modifications Copyright 2011, Blender Foundation.
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "mesh.h"
00019 #include "object.h"
00020 #include "scene.h"
00021 
00022 #include "bvh.h"
00023 #include "bvh_build.h"
00024 #include "bvh_node.h"
00025 #include "bvh_params.h"
00026 
00027 #include "util_cache.h"
00028 #include "util_debug.h"
00029 #include "util_foreach.h"
00030 #include "util_map.h"
00031 #include "util_progress.h"
00032 #include "util_types.h"
00033 
00034 CCL_NAMESPACE_BEGIN
00035 
00036 /* Pack Utility */
00037 
00038 struct BVHStackEntry
00039 {
00040     const BVHNode *node;
00041     int idx;
00042 
00043     BVHStackEntry(const BVHNode* n = 0, int i = 0)
00044     : node(n), idx(i)
00045     {
00046     }
00047 
00048     int encodeIdx() const
00049     {
00050         return (node->is_leaf())? ~idx: idx;
00051     }
00052 };
00053 
00054 /* BVH */
00055 
00056 BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
00057 : params(params_), objects(objects_)
00058 {
00059 }
00060 
00061 BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
00062 {
00063     if(params.use_qbvh)
00064         return new QBVH(params, objects);
00065     else
00066         return new RegularBVH(params, objects);
00067 }
00068 
00069 /* Cache */
00070 
00071 bool BVH::cache_read(CacheData& key)
00072 {
00073     key.add(&params, sizeof(params));
00074 
00075     foreach(Object *ob, objects) {
00076         key.add(ob->mesh->verts);
00077         key.add(ob->mesh->triangles);
00078         key.add(&ob->bounds, sizeof(ob->bounds));
00079         key.add(&ob->visibility, sizeof(ob->visibility));
00080         key.add(&ob->mesh->transform_applied, sizeof(bool));
00081     }
00082 
00083     CacheData value;
00084 
00085     if(Cache::global.lookup(key, value)) {
00086         cache_filename = key.get_filename();
00087 
00088         value.read(pack.root_index);
00089         value.read(pack.SAH);
00090 
00091         value.read(pack.nodes);
00092         value.read(pack.object_node);
00093         value.read(pack.tri_woop);
00094         value.read(pack.prim_visibility);
00095         value.read(pack.prim_index);
00096         value.read(pack.prim_object);
00097         value.read(pack.is_leaf);
00098 
00099         return true;
00100     }
00101 
00102     return false;
00103 }
00104 
00105 void BVH::cache_write(CacheData& key)
00106 {
00107     CacheData value;
00108 
00109     value.add(pack.root_index);
00110     value.add(pack.SAH);
00111 
00112     value.add(pack.nodes);
00113     value.add(pack.object_node);
00114     value.add(pack.tri_woop);
00115     value.add(pack.prim_visibility);
00116     value.add(pack.prim_index);
00117     value.add(pack.prim_object);
00118     value.add(pack.is_leaf);
00119 
00120     Cache::global.insert(key, value);
00121 
00122     cache_filename = key.get_filename();
00123 }
00124 
00125 void BVH::clear_cache_except()
00126 {
00127     set<string> except;
00128 
00129     if(!cache_filename.empty())
00130         except.insert(cache_filename);
00131 
00132     foreach(Object *ob, objects) {
00133         Mesh *mesh = ob->mesh;
00134         BVH *bvh = mesh->bvh;
00135 
00136         if(bvh && !bvh->cache_filename.empty())
00137             except.insert(bvh->cache_filename);
00138     }
00139 
00140     Cache::global.clear_except("bvh", except);
00141 }
00142 
00143 /* Building */
00144 
00145 void BVH::build(Progress& progress)
00146 {
00147     progress.set_substatus("Building BVH");
00148 
00149     /* cache read */
00150     CacheData key("bvh");
00151 
00152     if(params.use_cache) {
00153         progress.set_substatus("Looking in BVH cache");
00154 
00155         if(cache_read(key))
00156             return;
00157     }
00158 
00159     /* build nodes */
00160     vector<int> prim_index;
00161     vector<int> prim_object;
00162 
00163     BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
00164     BVHNode *root = bvh_build.run();
00165 
00166     if(progress.get_cancel()) {
00167         if(root) root->deleteSubtree();
00168         return;
00169     }
00170 
00171     /* todo: get rid of this copy */
00172     pack.prim_index = prim_index;
00173     pack.prim_object = prim_object;
00174 
00175     /* compute SAH */
00176     if(!params.top_level)
00177         pack.SAH = root->computeSubtreeSAHCost(params);
00178 
00179     if(progress.get_cancel()) {
00180         root->deleteSubtree();
00181         return;
00182     }
00183 
00184     /* pack triangles */
00185     progress.set_substatus("Packing BVH triangles");
00186     pack_triangles();
00187 
00188     if(progress.get_cancel()) {
00189         root->deleteSubtree();
00190         return;
00191     }
00192 
00193     /* pack nodes */
00194     progress.set_substatus("Packing BVH nodes");
00195     array<int> tmp_prim_object = pack.prim_object;
00196     pack_nodes(tmp_prim_object, root);
00197     
00198     /* free build nodes */
00199     root->deleteSubtree();
00200 
00201     if(progress.get_cancel()) return;
00202 
00203     /* cache write */
00204     if(params.use_cache) {
00205         progress.set_substatus("Writing BVH cache");
00206         cache_write(key);
00207 
00208         /* clear other bvh files from cache */
00209         if(params.top_level)
00210             clear_cache_except();
00211     }
00212 }
00213 
00214 /* Refitting */
00215 
00216 void BVH::refit(Progress& progress)
00217 {
00218     progress.set_substatus("Packing BVH triangles");
00219     pack_triangles();
00220 
00221     if(progress.get_cancel()) return;
00222 
00223     progress.set_substatus("Refitting BVH nodes");
00224     refit_nodes();
00225 }
00226 
00227 /* Triangles */
00228 
00229 void BVH::pack_triangle(int idx, float4 woop[3])
00230 {
00231     /* create Woop triangle */
00232     int tob = pack.prim_object[idx];
00233     const Mesh *mesh = objects[tob]->mesh;
00234     int tidx = pack.prim_index[idx];
00235     const int *vidx = mesh->triangles[tidx].v;
00236     const float3* vpos = &mesh->verts[0];
00237     float3 v0 = vpos[vidx[0]];
00238     float3 v1 = vpos[vidx[1]];
00239     float3 v2 = vpos[vidx[2]];
00240 
00241     float3 r0 = v0 - v2;
00242     float3 r1 = v1 - v2;
00243     float3 r2 = cross(r0, r1);
00244 
00245     if(dot(r0, r0) == 0.0f || dot(r1, r1) == 0.0f || dot(r2, r2) == 0.0f) {
00246         /* degenerate */
00247         woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00248         woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00249         woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00250     }
00251     else {
00252         Transform t = make_transform(
00253             r0.x, r1.x, r2.x, v2.x,
00254             r0.y, r1.y, r2.y, v2.y,
00255             r0.z, r1.z, r2.z, v2.z,
00256             0.0f, 0.0f, 0.0f, 1.0f);
00257 
00258         t = transform_inverse(t);
00259 
00260         woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w);
00261         woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w);
00262         woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w);
00263     }
00264 }
00265 
00266 void BVH::pack_triangles()
00267 {
00268     int nsize = TRI_NODE_SIZE;
00269     size_t tidx_size = pack.prim_index.size();
00270 
00271     pack.tri_woop.clear();
00272     pack.tri_woop.resize(tidx_size * nsize);
00273     pack.prim_visibility.clear();
00274     pack.prim_visibility.resize(tidx_size);
00275 
00276     for(unsigned int i = 0; i < tidx_size; i++) {
00277         if(pack.prim_index[i] != -1) {
00278             float4 woop[3];
00279 
00280             pack_triangle(i, woop);
00281             memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
00282 
00283             int tob = pack.prim_object[i];
00284             Object *ob = objects[tob];
00285             pack.prim_visibility[i] = ob->visibility;
00286         }
00287     }
00288 }
00289 
00290 /* Pack Instances */
00291 
00292 void BVH::pack_instances(size_t nodes_size)
00293 {
00294     /* The BVH's for instances are built separately, but for traversal all
00295        BVH's are stored in global arrays. This function merges them into the
00296        top level BVH, adjusting indexes and offsets where appropriate. */
00297     bool use_qbvh = params.use_qbvh;
00298     size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
00299 
00300     /* adjust primitive index to point to the triangle in the global array, for
00301        meshes with transform applied and already in the top level BVH */
00302     for(size_t i = 0; i < pack.prim_index.size(); i++)
00303         if(pack.prim_index[i] != -1)
00304             pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
00305 
00306     /* track offsets of instanced BVH data in global array */
00307     size_t tri_offset = pack.prim_index.size();
00308     size_t nodes_offset = nodes_size;
00309 
00310     /* clear array that gives the node indexes for instanced objects */
00311     pack.object_node.clear();
00312 
00313     /* reserve */
00314     size_t prim_index_size = pack.prim_index.size();
00315     size_t tri_woop_size = pack.tri_woop.size();
00316 
00317     size_t pack_prim_index_offset = prim_index_size;
00318     size_t pack_tri_woop_offset = tri_woop_size;
00319     size_t pack_nodes_offset = nodes_size;
00320     size_t object_offset = 0;
00321 
00322     map<Mesh*, int> mesh_map;
00323 
00324     foreach(Object *ob, objects) {
00325         Mesh *mesh = ob->mesh;
00326         BVH *bvh = mesh->bvh;
00327 
00328         if(!mesh->transform_applied) {
00329             if(mesh_map.find(mesh) == mesh_map.end()) {
00330                 prim_index_size += bvh->pack.prim_index.size();
00331                 tri_woop_size += bvh->pack.tri_woop.size();
00332                 nodes_size += bvh->pack.nodes.size()*nsize;
00333 
00334                 mesh_map[mesh] = 1;
00335             }
00336         }
00337     }
00338 
00339     mesh_map.clear();
00340 
00341     pack.prim_index.resize(prim_index_size);
00342     pack.prim_object.resize(prim_index_size);
00343     pack.prim_visibility.resize(prim_index_size);
00344     pack.tri_woop.resize(tri_woop_size);
00345     pack.nodes.resize(nodes_size);
00346     pack.object_node.resize(objects.size());
00347 
00348     int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
00349     int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
00350     uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
00351     float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
00352     int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
00353 
00354     /* merge */
00355     foreach(Object *ob, objects) {
00356         Mesh *mesh = ob->mesh;
00357 
00358         /* if mesh transform is applied, that means it's already in the top
00359            level BVH, and we don't need to merge it in */
00360         if(mesh->transform_applied) {
00361             pack.object_node[object_offset++] = 0;
00362             continue;
00363         }
00364 
00365         /* if mesh already added once, don't add it again, but used set
00366            node offset for this object */
00367         map<Mesh*, int>::iterator it = mesh_map.find(mesh);
00368 
00369         if(mesh_map.find(mesh) != mesh_map.end()) {
00370             int noffset = it->second;
00371             pack.object_node[object_offset++] = noffset;
00372             continue;
00373         }
00374 
00375         BVH *bvh = mesh->bvh;
00376 
00377         int noffset = nodes_offset/nsize;
00378         int mesh_tri_offset = mesh->tri_offset;
00379 
00380         /* fill in node indexes for instances */
00381         if(bvh->pack.is_leaf[0])
00382             pack.object_node[object_offset++] = -noffset-1;
00383         else
00384             pack.object_node[object_offset++] = noffset;
00385 
00386         mesh_map[mesh] = pack.object_node[object_offset-1];
00387 
00388         /* merge primitive and object indexes */
00389         if(bvh->pack.prim_index.size()) {
00390             size_t bvh_prim_index_size = bvh->pack.prim_index.size();
00391             int *bvh_prim_index = &bvh->pack.prim_index[0];
00392             uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
00393 
00394             for(size_t i = 0; i < bvh_prim_index_size; i++) {
00395                 pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
00396                 pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
00397                 pack_prim_object[pack_prim_index_offset] = 0;  // unused for instances
00398                 pack_prim_index_offset++;
00399             }
00400         }
00401 
00402         /* merge triangle intersection data */
00403         if(bvh->pack.tri_woop.size()) {
00404             memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
00405                 bvh->pack.tri_woop.size()*sizeof(float4));
00406             pack_tri_woop_offset += bvh->pack.tri_woop.size();
00407         }
00408 
00409         /* merge nodes */
00410         if( bvh->pack.nodes.size()) {
00411             size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1;
00412             int4 *bvh_nodes = &bvh->pack.nodes[0];
00413             size_t bvh_nodes_size = bvh->pack.nodes.size(); 
00414             int *bvh_is_leaf = &bvh->pack.is_leaf[0];
00415 
00416             for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
00417                 memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
00418 
00419                 /* modify offsets into arrays */
00420                 int4 data = bvh_nodes[i + nsize_bbox];
00421 
00422                 if(bvh_is_leaf[j]) {
00423                     data.x += tri_offset;
00424                     data.y += tri_offset;
00425                 }
00426                 else {
00427                     data.x += (data.x < 0)? -noffset: noffset;
00428                     data.y += (data.y < 0)? -noffset: noffset;
00429 
00430                     if(use_qbvh) {
00431                         data.z += (data.z < 0)? -noffset: noffset;
00432                         data.w += (data.w < 0)? -noffset: noffset;
00433                     }
00434                 }
00435 
00436                 pack_nodes[pack_nodes_offset + nsize_bbox] = data;
00437 
00438                 if(use_qbvh)
00439                     pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1];
00440 
00441                 pack_nodes_offset += nsize;
00442             }
00443         }
00444 
00445         nodes_offset += bvh->pack.nodes.size();
00446         tri_offset += bvh->pack.prim_index.size();
00447     }
00448 }
00449 
00450 /* Regular BVH */
00451 
00452 RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
00453 : BVH(params_, objects_)
00454 {
00455 }
00456 
00457 void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
00458 {
00459     if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
00460         /* object */
00461         pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, leaf->m_visibility, leaf->m_visibility);
00462     else
00463         /* triangle */
00464         pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility);
00465 }
00466 
00467 void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
00468 {
00469     pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
00470 }
00471 
00472 void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
00473 {
00474     int4 data[BVH_NODE_SIZE] =
00475     {
00476         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)),
00477         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)),
00478         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)),
00479         make_int4(c0, c1, visibility0, visibility1)
00480     };
00481 
00482     memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
00483 }
00484 
00485 void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
00486 {
00487     size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
00488 
00489     /* resize arrays */
00490     pack.nodes.clear();
00491     pack.is_leaf.clear();
00492     pack.is_leaf.resize(node_size);
00493 
00494     /* for top level BVH, first merge existing BVH's so we know the offsets */
00495     if(params.top_level)
00496         pack_instances(node_size*BVH_NODE_SIZE);
00497     else
00498         pack.nodes.resize(node_size*BVH_NODE_SIZE);
00499 
00500     int nextNodeIdx = 0;
00501 
00502     vector<BVHStackEntry> stack;
00503     stack.push_back(BVHStackEntry(root, nextNodeIdx++));
00504 
00505     while(stack.size()) {
00506         BVHStackEntry e = stack.back();
00507         stack.pop_back();
00508 
00509         pack.is_leaf[e.idx] = e.node->is_leaf();
00510 
00511         if(e.node->is_leaf()) {
00512             /* leaf node */
00513             const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
00514             pack_leaf(e, leaf);
00515         }
00516         else {
00517             /* innner node */
00518             stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
00519             stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
00520 
00521             pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
00522         }
00523     }
00524 
00525     /* root index to start traversal at, to handle case of single leaf node */
00526     pack.root_index = (pack.is_leaf[0])? -1: 0;
00527 }
00528 
00529 void RegularBVH::refit_nodes()
00530 {
00531     assert(!params.top_level);
00532 
00533     BoundBox bbox;
00534     uint visibility = 0;
00535     refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
00536 }
00537 
00538 void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
00539 {
00540     int4 *data = &pack.nodes[idx*4];
00541 
00542     int c0 = data[3].x;
00543     int c1 = data[3].y;
00544 
00545     if(leaf) {
00546         /* refit leaf node */
00547         for(int tri = c0; tri < c1; tri++) {
00548             int tidx = pack.prim_index[tri];
00549             int tob = pack.prim_object[tri];
00550             Object *ob = objects[tob];
00551 
00552             if(tidx == -1) {
00553                 /* object instance */
00554                 bbox.grow(ob->bounds);
00555             }
00556             else {
00557                 /* triangles */
00558                 const Mesh *mesh = ob->mesh;
00559                 int tri_offset = (params.top_level)? mesh->tri_offset: 0;
00560                 const int *vidx = mesh->triangles[tidx - tri_offset].v;
00561                 const float3 *vpos = &mesh->verts[0];
00562 
00563                 bbox.grow(vpos[vidx[0]]);
00564                 bbox.grow(vpos[vidx[1]]);
00565                 bbox.grow(vpos[vidx[2]]);
00566             }
00567 
00568             visibility |= ob->visibility;
00569         }
00570 
00571         pack_node(idx, bbox, bbox, c0, c1, visibility, visibility);
00572     }
00573     else {
00574         /* refit inner node, set bbox from children */
00575         BoundBox bbox0, bbox1;
00576         uint visibility0 = 0, visibility1 = 0;
00577 
00578         refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
00579         refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
00580 
00581         pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
00582 
00583         bbox.grow(bbox0);
00584         bbox.grow(bbox1);
00585         visibility = visibility0|visibility1;
00586     }
00587 }
00588 
00589 /* QBVH */
00590 
00591 QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
00592 : BVH(params_, objects_)
00593 {
00594     params.use_qbvh = true;
00595 
00596     /* todo: use visibility */
00597 }
00598 
00599 void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
00600 {
00601     float4 data[BVH_QNODE_SIZE];
00602 
00603     memset(data, 0, sizeof(data));
00604 
00605     if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
00606         /* object */
00607         data[6].x = __int_as_float(~(leaf->m_lo));
00608         data[6].y = __int_as_float(0);
00609     }
00610     else {
00611         /* triangle */
00612         data[6].x = __int_as_float(leaf->m_lo);
00613         data[6].y = __int_as_float(leaf->m_hi);
00614     }
00615 
00616     memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
00617 }
00618 
00619 void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
00620 {
00621     float4 data[BVH_QNODE_SIZE];
00622 
00623     for(int i = 0; i < num; i++) {
00624         float3 bb_min = en[i].node->m_bounds.min;
00625         float3 bb_max = en[i].node->m_bounds.max;
00626 
00627         data[0][i] = bb_min.x;
00628         data[1][i] = bb_max.x;
00629         data[2][i] = bb_min.y;
00630         data[3][i] = bb_max.y;
00631         data[4][i] = bb_min.z;
00632         data[5][i] = bb_max.z;
00633 
00634         data[6][i] = __int_as_float(en[i].encodeIdx());
00635         data[7][i] = 0.0f;
00636     }
00637 
00638     for(int i = num; i < 4; i++) {
00639         data[0][i] = 0.0f;
00640         data[1][i] = 0.0f;
00641         data[2][i] = 0.0f;
00642 
00643         data[3][i] = 0.0f;
00644         data[4][i] = 0.0f;
00645         data[5][i] = 0.0f;
00646 
00647         data[6][i] = __int_as_float(0);
00648         data[7][i] = 0.0f;
00649     }
00650 
00651     memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
00652 }
00653 
00654 /* Quad SIMD Nodes */
00655 
00656 void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
00657 {
00658     size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
00659 
00660     /* resize arrays */
00661     pack.nodes.clear();
00662     pack.is_leaf.clear();
00663     pack.is_leaf.resize(node_size);
00664 
00665     /* for top level BVH, first merge existing BVH's so we know the offsets */
00666     if(params.top_level)
00667         pack_instances(node_size*BVH_QNODE_SIZE);
00668     else
00669         pack.nodes.resize(node_size*BVH_QNODE_SIZE);
00670 
00671     int nextNodeIdx = 0;
00672 
00673     vector<BVHStackEntry> stack;
00674     stack.push_back(BVHStackEntry(root, nextNodeIdx++));
00675 
00676     while(stack.size()) {
00677         BVHStackEntry e = stack.back();
00678         stack.pop_back();
00679 
00680         pack.is_leaf[e.idx] = e.node->is_leaf();
00681 
00682         if(e.node->is_leaf()) {
00683             /* leaf node */
00684             const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
00685             pack_leaf(e, leaf);
00686         }
00687         else {
00688             /* inner node */
00689             const BVHNode *node = e.node;
00690             const BVHNode *node0 = node->get_child(0);
00691             const BVHNode *node1 = node->get_child(1);
00692 
00693             /* collect nodes */
00694             const BVHNode *nodes[4];
00695             int numnodes = 0;
00696 
00697             if(node0->is_leaf()) {
00698                 nodes[numnodes++] = node0;
00699             }
00700             else {
00701                 nodes[numnodes++] = node0->get_child(0);
00702                 nodes[numnodes++] = node0->get_child(1);
00703             }
00704 
00705             if(node1->is_leaf()) {
00706                 nodes[numnodes++] = node1;
00707             }
00708             else {
00709                 nodes[numnodes++] = node1->get_child(0);
00710                 nodes[numnodes++] = node1->get_child(1);
00711             }
00712 
00713             /* push entries on the stack */
00714             for(int i = 0; i < numnodes; i++)
00715                 stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
00716 
00717             /* set node */
00718             pack_inner(e, &stack[stack.size()-numnodes], numnodes);
00719         }
00720     }
00721 
00722     /* root index to start traversal at, to handle case of single leaf node */
00723     pack.root_index = (pack.is_leaf[0])? -1: 0;
00724 }
00725 
00726 void QBVH::refit_nodes()
00727 {
00728     assert(0); /* todo */
00729 }
00730 
00731 CCL_NAMESPACE_END
00732