diff --git a/rtiow/renderer/src/bvh_triangles.rs b/rtiow/renderer/src/bvh_triangles.rs index 4b15359..4113ab6 100644 --- a/rtiow/renderer/src/bvh_triangles.rs +++ b/rtiow/renderer/src/bvh_triangles.rs @@ -59,6 +59,12 @@ where bvh_nodes: Vec, } +#[derive(Debug, Default)] +struct Bin { + bounds: AABB, + tri_count: usize, +} + impl fmt::Debug for BVHTriangles 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 { let mut node = &self.bvh_nodes[ROOT_NODE_IDX]; let mut stack = Vec::with_capacity(2);