rtiow: BVHTriangles use binning to speed up BVH building.
This commit is contained in:
parent
7d9750b9d0
commit
1076e6dcaf
@ -59,6 +59,12 @@ where
|
||||
bvh_nodes: Vec<BVHNode>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Bin {
|
||||
bounds: AABB,
|
||||
tri_count: usize,
|
||||
}
|
||||
|
||||
impl<M> fmt::Debug for BVHTriangles<M>
|
||||
where
|
||||
M: Material,
|
||||
@ -102,6 +108,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SplitCost {
|
||||
pos: f32,
|
||||
axis: usize,
|
||||
@ -175,6 +182,7 @@ where
|
||||
info!("BVHTriangles build stats:");
|
||||
info!(" Nodes: {}", stats.nodes);
|
||||
info!(" Leaves: {}", stats.leafs);
|
||||
info!(" Tris: {}", bvh.triangles.len());
|
||||
info!(" Min Tri: {}", stats.min_tris);
|
||||
info!(" Max Tri: {}", stats.max_tris);
|
||||
info!(" Avg Tri: {}", bvh.triangles.len() / stats.leafs);
|
||||
@ -226,20 +234,71 @@ where
|
||||
};
|
||||
|
||||
for axis in 0..3 {
|
||||
let bounds_min = node.aabb.min()[axis];
|
||||
let bounds_max = node.aabb.max()[axis];
|
||||
let mut bounds_min = f32::MAX;
|
||||
let mut bounds_max = f32::MIN;
|
||||
|
||||
for i in 0..node.tri_count {
|
||||
let triangle = &self.triangles[self.triangle_index[(node.left_first + i) as usize]];
|
||||
bounds_min = bounds_min.min(triangle.centroid[axis]);
|
||||
bounds_max = bounds_max.max(triangle.centroid[axis]);
|
||||
}
|
||||
|
||||
if bounds_min == bounds_max {
|
||||
continue;
|
||||
}
|
||||
let scale = (bounds_max - bounds_min) / 100.;
|
||||
|
||||
for i in 0..100 {
|
||||
let candidate_pos = bounds_min + (i as f32) * scale;
|
||||
let cost = self.evaluate_sah(node, axis, candidate_pos);
|
||||
if cost <= best.cost {
|
||||
best.pos = candidate_pos;
|
||||
const NUM_BINS: usize = 8;
|
||||
let mut bins: Vec<_> = (0..NUM_BINS)
|
||||
.map(|_| Bin {
|
||||
bounds: AABB::infinite(),
|
||||
tri_count: 0,
|
||||
})
|
||||
.collect();
|
||||
let scale = bins.len() as f32 / (bounds_max - bounds_min);
|
||||
// populate the bins
|
||||
for i in 0..node.tri_count {
|
||||
let triangle = &self.triangles[self.triangle_index[(node.left_first + i) as usize]];
|
||||
let bin_idx = (triangle.centroid[axis] - bounds_min) * scale;
|
||||
let bin_idx = (bins.len() - 1).min(bin_idx as usize);
|
||||
|
||||
bins[bin_idx].tri_count += 1;
|
||||
bins[bin_idx].bounds.grow(triangle.verts[0]);
|
||||
bins[bin_idx].bounds.grow(triangle.verts[1]);
|
||||
bins[bin_idx].bounds.grow(triangle.verts[2]);
|
||||
}
|
||||
|
||||
// gather data for the 7 planes between the 8 bins
|
||||
let mut left_area: Vec<_> = (0..bins.len() - 1).map(|_| 0.).collect();
|
||||
let mut right_area: Vec<_> = (0..bins.len() - 1).map(|_| 0.).collect();
|
||||
let mut left_count: Vec<_> = (0..bins.len() - 1).map(|_| 0).collect();
|
||||
let mut right_count: Vec<_> = (0..bins.len() - 1).map(|_| 0).collect();
|
||||
let mut left_box = AABB::infinite();
|
||||
let mut right_box = AABB::infinite();
|
||||
let mut left_sum = 0;
|
||||
let mut right_sum = 0;
|
||||
for i in 0..(bins.len() - 1) {
|
||||
left_sum += bins[i].tri_count;
|
||||
left_count[i] = left_sum;
|
||||
left_box.grow(bins[i].bounds.min());
|
||||
left_box.grow(bins[i].bounds.max());
|
||||
left_area[i] = left_box.area();
|
||||
|
||||
right_sum += bins[bins.len() - 1 - i].tri_count;
|
||||
right_count[bins.len() - 2 - i] = right_sum;
|
||||
right_box.grow(bins[bins.len() - 1 - i].bounds.min());
|
||||
right_box.grow(bins[bins.len() - 1 - i].bounds.max());
|
||||
right_area[bins.len() - 2 - i] = right_box.area();
|
||||
}
|
||||
|
||||
let scale = (bounds_max - bounds_min) / bins.len() as f32;
|
||||
// calculate SAH cost for the 7 planes
|
||||
for i in 0..(bins.len() - 1) {
|
||||
let plane_cost =
|
||||
left_count[i] as f32 * left_area[i] + right_count[i] as f32 * right_area[i];
|
||||
if plane_cost < best.cost {
|
||||
best.axis = axis;
|
||||
best.cost = cost;
|
||||
best.pos = bounds_min + scale * (i as f32 + 1.);
|
||||
best.cost = plane_cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,34 +365,6 @@ where
|
||||
self.subdivide(right_child_idx as usize);
|
||||
}
|
||||
|
||||
fn evaluate_sah(&self, node: &BVHNode, axis: usize, pos: f32) -> f32 {
|
||||
// determine triangle counts and bounds for this split candidate
|
||||
let mut left_box = AABB::infinite();
|
||||
let mut right_box = AABB::infinite();
|
||||
let mut left_count = 0;
|
||||
let mut right_count = 0;
|
||||
for i in 0..node.tri_count {
|
||||
let triangle = &self.triangles[self.triangle_index[(node.left_first + i) as usize]];
|
||||
if triangle.centroid[axis] < pos {
|
||||
left_count += 1;
|
||||
left_box.grow(triangle.verts[0]);
|
||||
left_box.grow(triangle.verts[1]);
|
||||
left_box.grow(triangle.verts[2]);
|
||||
} else {
|
||||
right_count += 1;
|
||||
right_box.grow(triangle.verts[0]);
|
||||
right_box.grow(triangle.verts[1]);
|
||||
right_box.grow(triangle.verts[2]);
|
||||
}
|
||||
}
|
||||
let cost = left_count as f32 * left_box.area() + right_count as f32 * right_box.area();
|
||||
if cost > 0. {
|
||||
cost
|
||||
} else {
|
||||
f32::MAX
|
||||
}
|
||||
}
|
||||
|
||||
fn intersect_bvh(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let mut node = &self.bvh_nodes[ROOT_NODE_IDX];
|
||||
let mut stack = Vec::with_capacity(2);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user