diff options
Diffstat (limited to 'intern/cycles/bvh/bvh.cpp')
-rw-r--r-- | intern/cycles/bvh/bvh.cpp | 287 |
1 files changed, 192 insertions, 95 deletions
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 15bd814b8d5..9fa602f0952 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -205,6 +205,9 @@ void BVH::build(Progress& progress) pack.prim_type = prim_type; pack.prim_index = prim_index; pack.prim_object = prim_object; + prim_type.free_memory(); + prim_index.free_memory(); + prim_object.free_memory(); /* compute SAH */ if(!params.top_level) @@ -226,9 +229,8 @@ void BVH::build(Progress& progress) /* pack nodes */ progress.set_substatus("Packing BVH nodes"); - array<int> tmp_prim_object = pack.prim_object; - pack_nodes(tmp_prim_object, root); - + pack_nodes(root); + /* free build nodes */ root->deleteSubtree(); @@ -263,11 +265,9 @@ void BVH::refit(Progress& progress) void BVH::pack_triangle(int idx, float4 woop[3]) { int tob = pack.prim_object[idx]; + assert(tob >= 0 && tob < objects.size()); const Mesh *mesh = objects[tob]->mesh; - if(mesh->has_motion_blur()) - return; - int tidx = pack.prim_index[idx]; const int *vidx = mesh->triangles[tidx].v; const float3* vpos = &mesh->verts[0]; @@ -275,68 +275,13 @@ void BVH::pack_triangle(int idx, float4 woop[3]) float3 v1 = vpos[vidx[1]]; float3 v2 = vpos[vidx[2]]; - float3 r0 = v0 - v2; - float3 r1 = v1 - v2; - float3 r2 = cross(r0, r1); - - if(is_zero(r0) || is_zero(r1) || is_zero(r2)) { - /* degenerate */ - woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - else { - Transform t = make_transform( - r0.x, r1.x, r2.x, v2.x, - r0.y, r1.y, r2.y, v2.y, - r0.z, r1.z, r2.z, v2.z, - 0.0f, 0.0f, 0.0f, 1.0f); - - t = transform_inverse(t); - - woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w); - woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w); - woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w); - } + woop[0] = float3_to_float4(v0); + woop[1] = float3_to_float4(v1); + woop[2] = float3_to_float4(v2); } /* Curves*/ -void BVH::pack_curve_segment(int idx, float4 woop[3]) -{ - int tob = pack.prim_object[idx]; - const Mesh *mesh = objects[tob]->mesh; - int tidx = pack.prim_index[idx]; - int segment = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[idx]); - int k0 = mesh->curves[tidx].first_key + segment; - int k1 = mesh->curves[tidx].first_key + segment + 1; - float3 v0 = float4_to_float3(mesh->curve_keys[k0]); - float3 v1 = float4_to_float3(mesh->curve_keys[k1]); - - float3 d0 = v1 - v0; - float l = len(d0); - - /*Plan - *Transform tfm = make_transform( - * location <3> , l, - * extra curve data <3> , StrID, - * nextkey, flags/tip?, 0, 0); - */ - float3 tg0 = make_float3(1.0f, 0.0f, 0.0f); - float3 tg1 = make_float3(1.0f, 0.0f, 0.0f); - - Transform tfm = make_transform( - tg0.x, tg0.y, tg0.z, l, - tg1.x, tg1.y, tg1.z, 0, - 0, 0, 0, 0, - 0, 0, 0, 1); - - woop[0] = tfm.x; - woop[1] = tfm.y; - woop[2] = tfm.z; - -} - void BVH::pack_primitives() { int nsize = TRI_NODE_SIZE; @@ -351,11 +296,14 @@ void BVH::pack_primitives() if(pack.prim_index[i] != -1) { float4 woop[3]; - if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) - pack_curve_segment(i, woop); - else + if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) { pack_triangle(i, woop); - + } + else { + /* Avoid use of uninitialized memory. */ + memset(&woop, 0, sizeof(woop)); + } + memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3); int tob = pack.prim_object[i]; @@ -418,7 +366,7 @@ void BVH::pack_instances(size_t nodes_size) if(mesh_map.find(mesh) == mesh_map.end()) { prim_index_size += bvh->pack.prim_index.size(); tri_woop_size += bvh->pack.tri_woop.size(); - nodes_size += bvh->pack.nodes.size()*nsize; + nodes_size += bvh->pack.nodes.size(); mesh_map[mesh] = 1; } @@ -506,10 +454,13 @@ void BVH::pack_instances(size_t nodes_size) /* merge nodes */ if(bvh->pack.nodes.size()) { - size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1; + /* For QBVH we're packing a child bbox into 6 float4, + * and for regular BVH they're packed into 3 float4. + */ + size_t nsize_bbox = (use_qbvh)? 6: 3; int4 *bvh_nodes = &bvh->pack.nodes[0]; size_t bvh_nodes_size = bvh->pack.nodes.size(); - int *bvh_is_leaf = (bvh->pack.is_leaf.size() != 0) ? &bvh->pack.is_leaf[0] : NULL; + bool *bvh_is_leaf = (bvh->pack.is_leaf.size() != 0) ? &bvh->pack.is_leaf[0] : NULL; for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) { memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4)); @@ -533,8 +484,12 @@ void BVH::pack_instances(size_t nodes_size) pack_nodes[pack_nodes_offset + nsize_bbox] = data; - if(use_qbvh) - pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1]; + /* 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; } @@ -554,12 +509,20 @@ RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) { - if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) + if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) { /* object */ - pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, leaf->m_visibility, leaf->m_visibility); - else - /* triangle */ - pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility); + pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0, + leaf->m_visibility, leaf->m_visibility); + } + else { + int prim_type = leaf->num_triangles() ? pack.prim_type[leaf->m_lo] : 0; + /* Triangle/curve primitive leaf. */ + pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, + leaf->m_lo, leaf->m_hi, + leaf->m_visibility, + prim_type); + } + } void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1) @@ -580,7 +543,7 @@ void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE); } -void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root) +void RegularBVH::pack_nodes(const BVHNode *root) { size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT); @@ -636,7 +599,7 @@ void RegularBVH::refit_nodes() void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { - int4 *data = &pack.nodes[idx*4]; + int4 *data = &pack.nodes[idx*BVH_NODE_SIZE]; int c0 = data[3].x; int c1 = data[3].y; @@ -707,7 +670,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility visibility |= ob->visibility; } - pack_node(idx, bbox, bbox, c0, c1, visibility, visibility); + pack_node(idx, bbox, bbox, c0, c1, visibility, data[3].w); } else { /* refit inner node, set bbox from children */ @@ -731,8 +694,6 @@ QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_) : BVH(params_, objects_) { params.use_qbvh = true; - - /* todo: use visibility */ } void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) @@ -751,6 +712,10 @@ void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) data[6].x = __int_as_float(leaf->m_lo); data[6].y = __int_as_float(leaf->m_hi); } + data[6].z = __uint_as_float(leaf->m_visibility); + if(leaf->num_triangles() != 0) { + data[6].w = __uint_as_float(pack.prim_type[leaf->m_lo]); + } memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE); } @@ -771,20 +736,22 @@ void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num) data[5][i] = bb_max.z; data[6][i] = __int_as_float(en[i].encodeIdx()); - data[7][i] = 0.0f; } for(int i = num; i < 4; i++) { - data[0][i] = 0.0f; - data[1][i] = 0.0f; - data[2][i] = 0.0f; + /* We store BB which would never be recorded as intersection + * so kernel might safely assume there are always 4 child nodes. + */ + data[0][i] = FLT_MAX; + data[1][i] = -FLT_MAX; - data[3][i] = 0.0f; - data[4][i] = 0.0f; - data[5][i] = 0.0f; + data[2][i] = FLT_MAX; + data[3][i] = -FLT_MAX; + + data[4][i] = FLT_MAX; + data[5][i] = -FLT_MAX; data[6][i] = __int_as_float(0); - data[7][i] = 0.0f; } memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE); @@ -792,9 +759,9 @@ void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num) /* Quad SIMD Nodes */ -void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root) +void QBVH::pack_nodes(const BVHNode *root) { - size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT); + size_t node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); /* resize arrays */ pack.nodes.clear(); @@ -865,8 +832,138 @@ void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root) void QBVH::refit_nodes() { - assert(0); /* todo */ + assert(!params.top_level); + + BoundBox bbox = BoundBox::empty; + uint visibility = 0; + refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility); } -CCL_NAMESPACE_END +void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) +{ + int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE]; + int4 c = data[6]; + if(leaf) { + /* 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; + const Mesh::Curve& curve = mesh->curves[pidx - str_offset]; + int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); + + curve.bounds_grow(k, &mesh->curve_keys[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; + float4 *key_steps = attr->data_float4(); + + for (size_t i = 0; i < steps; i++) + curve.bounds_grow(k, key_steps + i*mesh_size, bbox); + } + } + } + else { + /* Triangles. */ + int tri_offset = (params.top_level)? mesh->tri_offset: 0; + const Mesh::Triangle& triangle = mesh->triangles[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; + } + + /* 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_SIZE]; + memset(leaf_data, 0, sizeof(leaf_data)); + leaf_data[6].x = __int_as_float(c.x); + leaf_data[6].y = __int_as_float(c.y); + leaf_data[6].z = __uint_as_float(visibility); + leaf_data[6].w = __uint_as_float(c.w); + memcpy(&pack.nodes[idx * BVH_QNODE_SIZE], + leaf_data, + sizeof(float4)*BVH_QNODE_SIZE); + } + else { + /* 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]; + } + } + + float4 inner_data[BVH_QNODE_SIZE]; + for(int i = 0; i < 4; ++i) { + float3 bb_min = child_bbox[i].min; + float3 bb_max = child_bbox[i].max; + inner_data[0][i] = bb_min.x; + inner_data[1][i] = bb_max.x; + inner_data[2][i] = bb_min.y; + inner_data[3][i] = bb_max.y; + inner_data[4][i] = bb_min.z; + inner_data[5][i] = bb_max.z; + inner_data[6][i] = __int_as_float(c[i]); + } + memcpy(&pack.nodes[idx * BVH_QNODE_SIZE], + inner_data, + sizeof(float4)*BVH_QNODE_SIZE); + } +} + +CCL_NAMESPACE_END |