diff options
Diffstat (limited to 'intern/cycles/bvh/bvh_split.cpp')
-rw-r--r-- | intern/cycles/bvh/bvh_split.cpp | 237 |
1 files changed, 182 insertions, 55 deletions
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 07c35c08c18..534c1aa73b5 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -191,11 +191,16 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, } } - /* duplicate or unsplit references intersecting both sides. */ + /* 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; + new_refs.reserve(right_start - left_end); while(left_end < right_start) { /* split reference. */ BVHReference lref, rref; - split_reference(builder, lref, rref, refs[left_end], this->dim, this->pos); /* compute SAH for duplicate/unsplit candidates. */ @@ -234,61 +239,36 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, left_bounds = ldb; right_bounds = rdb; refs[left_end++] = lref; - refs.insert(refs.begin() + right_end, rref); + 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()); + } left = BVHRange(left_bounds, left_start, left_end - left_start); right = BVHRange(right_bounds, right_start, right_end - right_start); } -void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVHReference& right, const BVHReference& ref, int dim, float pos) +void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh, + const Transform *tfm, + int prim_index, + int dim, + float pos, + BoundBox& left_bounds, + BoundBox& right_bounds) { - /* initialize boundboxes */ - BoundBox left_bounds = BoundBox::empty; - BoundBox right_bounds = BoundBox::empty; - - /* loop over vertices/edges. */ - Object *ob = builder->objects[ref.prim_object()]; - const Mesh *mesh = ob->mesh; - - if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) { - const int *inds = mesh->triangles[ref.prim_index()].v; - const float3 *verts = &mesh->verts[0]; - const float3* v1 = &verts[inds[2]]; - - for(int i = 0; i < 3; i++) { - const float3* v0 = v1; - int vindex = inds[i]; - v1 = &verts[vindex]; - 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); - } - } - } - else { - /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ - const int k0 = mesh->curves[ref.prim_index()].first_key + PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()); - const int k1 = k0 + 1; - const float4 key0 = mesh->curve_keys[k0]; - const float4 key1 = mesh->curve_keys[k1]; - const float3 v0 = float4_to_float3(key0); - const float3 v1 = float4_to_float3(key1); - + const int *inds = mesh->triangles[prim_index].v; + const float3 *verts = &mesh->verts[0]; + float3 v1 = tfm ? transform_point(tfm, verts[inds[2]]) : verts[inds[2]]; + + for(int i = 0; i < 3; i++) { + float3 v0 = v1; + int vindex = inds[i]; + v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex]; float v0p = v0[dim]; float v1p = v1[dim]; @@ -299,12 +279,6 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH 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)); @@ -312,6 +286,159 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH right_bounds.grow(t); } } +} + +void BVHSpatialSplit::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) +{ + /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ + const int k0 = mesh->curves[prim_index].first_key + segment_index; + const int k1 = k0 + 1; + const float4& key0 = mesh->curve_keys[k0]; + const float4& key1 = mesh->curve_keys[k1]; + float3 v0 = float4_to_float3(key0); + float3 v1 = float4_to_float3(key1); + + if(tfm != NULL) { + v0 = transform_point(tfm, v0); + v1 = transform_point(tfm, 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, + const Mesh *mesh, + int dim, + float pos, + BoundBox& left_bounds, + BoundBox& right_bounds) +{ + split_triangle_primitive(mesh, + NULL, + ref.prim_index(), + dim, + pos, + left_bounds, + right_bounds); +} + +void BVHSpatialSplit::split_curve_reference(const BVHReference& ref, + const Mesh *mesh, + int dim, + float pos, + 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); +} + +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->triangles.size(); ++tri_idx) { + split_triangle_primitive(mesh, + &object->tfm, + tri_idx, + dim, + pos, + left_bounds, + right_bounds); + } + for(int curve_idx = 0; curve_idx < mesh->curves.size(); ++curve_idx) { + Mesh::Curve &curve = mesh->curves[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(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. */ + 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; |