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>,
|
bvh_nodes: Vec<BVHNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Bin {
|
||||||
|
bounds: AABB,
|
||||||
|
tri_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> fmt::Debug for BVHTriangles<M>
|
impl<M> fmt::Debug for BVHTriangles<M>
|
||||||
where
|
where
|
||||||
M: Material,
|
M: Material,
|
||||||
@ -102,6 +108,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct SplitCost {
|
struct SplitCost {
|
||||||
pos: f32,
|
pos: f32,
|
||||||
axis: usize,
|
axis: usize,
|
||||||
@ -175,6 +182,7 @@ where
|
|||||||
info!("BVHTriangles build stats:");
|
info!("BVHTriangles build stats:");
|
||||||
info!(" Nodes: {}", stats.nodes);
|
info!(" Nodes: {}", stats.nodes);
|
||||||
info!(" Leaves: {}", stats.leafs);
|
info!(" Leaves: {}", stats.leafs);
|
||||||
|
info!(" Tris: {}", bvh.triangles.len());
|
||||||
info!(" Min Tri: {}", stats.min_tris);
|
info!(" Min Tri: {}", stats.min_tris);
|
||||||
info!(" Max Tri: {}", stats.max_tris);
|
info!(" Max Tri: {}", stats.max_tris);
|
||||||
info!(" Avg Tri: {}", bvh.triangles.len() / stats.leafs);
|
info!(" Avg Tri: {}", bvh.triangles.len() / stats.leafs);
|
||||||
@ -226,20 +234,71 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
for axis in 0..3 {
|
for axis in 0..3 {
|
||||||
let bounds_min = node.aabb.min()[axis];
|
let mut bounds_min = f32::MAX;
|
||||||
let bounds_max = node.aabb.max()[axis];
|
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 {
|
if bounds_min == bounds_max {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let scale = (bounds_max - bounds_min) / 100.;
|
|
||||||
|
|
||||||
for i in 0..100 {
|
const NUM_BINS: usize = 8;
|
||||||
let candidate_pos = bounds_min + (i as f32) * scale;
|
let mut bins: Vec<_> = (0..NUM_BINS)
|
||||||
let cost = self.evaluate_sah(node, axis, candidate_pos);
|
.map(|_| Bin {
|
||||||
if cost <= best.cost {
|
bounds: AABB::infinite(),
|
||||||
best.pos = candidate_pos;
|
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.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);
|
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> {
|
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 node = &self.bvh_nodes[ROOT_NODE_IDX];
|
||||||
let mut stack = Vec::with_capacity(2);
|
let mut stack = Vec::with_capacity(2);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user