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); }
bool operator()(const BVHReference& ra, const BVHReference& rb) { NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim]; NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim]; if(ca < cb) return true; else if(ca > cb) return false; else if(ra.prim_object() < rb.prim_object()) return true; else if(ra.prim_object() > rb.prim_object()) return false; else if(ra.prim_index() < rb.prim_index()) return true; else if(ra.prim_index() > rb.prim_index()) return false; else if(ra.prim_segment() < rb.prim_segment()) return true; else if(ra.prim_segment() > rb.prim_segment()) return false; return false; }
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_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()); }
BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, float nodeSAH) : sah(FLT_MAX), dim(0), pos(0.0f), storage_(storage), references_(references) { /* initialize bins. */ 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); float3 firstBinf = (ref.bounds().min - origin) * invBinSize; float3 lastBinf = (ref.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 = ref; 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. */ for(int dim = 0; dim < 3; dim++) { /* sweep right to left and determine bounds. */ BoundBox right_bounds = BoundBox::empty; storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS); 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; } } } }