void BVHObjectSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range) { /* sort references according to split */ bvh_reference_sort(range.start(), range.end(), &builder->references[0], this->dim); /* split node ranges */ left = BVHRange(this->left_bounds, range.start(), this->num_left); right = BVHRange(this->right_bounds, left.end(), range.size() - this->num_left); }
void BVHBuild::add_references(BVHRange& root) { /* reserve space for references */ size_t num_alloc_references = 0; foreach(Object *ob, objects) { if(params.top_level) { if(!ob->mesh->is_instanced()) { num_alloc_references += ob->mesh->triangles.size(); num_alloc_references += count_curve_segments(ob->mesh); } else num_alloc_references++; } else { num_alloc_references += ob->mesh->triangles.size(); num_alloc_references += count_curve_segments(ob->mesh); } } references.reserve(num_alloc_references); /* add references from objects */ BoundBox bounds = BoundBox::empty, center = BoundBox::empty; int i = 0; foreach(Object *ob, objects) { if(params.top_level) { if(!ob->mesh->is_instanced()) add_reference_mesh(bounds, center, ob->mesh, i); else add_reference_object(bounds, center, ob, i); } else add_reference_mesh(bounds, center, ob->mesh, i); i++; if(progress.get_cancel()) return; } /* happens mostly on empty meshes */ if(!bounds.valid()) bounds.grow(make_float3(0.0f, 0.0f, 0.0f)); root = BVHRange(bounds, center, 0, references.size()); }
void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range) { /* Categorize references and compute bounds. * * Left-hand side: [left_start, left_end[ * Uncategorized/split: [left_end, right_start[ * Right-hand side: [right_start, refs.size()[ */ vector<BVHReference>& refs = *references_; int left_start = range.start(); int left_end = left_start; int right_start = range.end(); int right_end = range.end(); BoundBox left_bounds = BoundBox::empty; BoundBox right_bounds = BoundBox::empty; for(int i = left_end; i < right_start; i++) { if(refs[i].bounds().max[this->dim] <= this->pos) { /* entirely on the left-hand side */ left_bounds.grow(refs[i].bounds()); swap(refs[i], refs[left_end++]); } else if(refs[i].bounds().min[this->dim] >= this->pos) { /* entirely on the right-hand side */ right_bounds.grow(refs[i].bounds()); swap(refs[i--], refs[--right_start]); } } /* 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 = storage_->new_references; new_refs.clear(); 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. */ BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds. BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds. BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds. BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds. lub.grow(refs[left_end].bounds()); rub.grow(refs[left_end].bounds()); ldb.grow(lref.bounds()); rdb.grow(rref.bounds()); float lac = builder->params.primitive_cost(left_end - left_start); float rac = builder->params.primitive_cost(right_end - right_start); float lbc = builder->params.primitive_cost(left_end - left_start + 1); float rbc = builder->params.primitive_cost(right_end - right_start + 1); float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac; float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc; float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc; float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH); if(minSAH == unsplitLeftSAH) { /* unsplit to left */ left_bounds = lub; left_end++; } else if(minSAH == unsplitRightSAH) { /* unsplit to right */ right_bounds = rub; swap(refs[left_end], refs[--right_start]); } else { /* duplicate */ left_bounds = ldb; right_bounds = rdb; refs[left_end++] = lref; 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); }