From c1b063411fab24d4c6a255b5939631d651a7823c Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 3 Jan 2016 21:21:46 -0800 Subject: [PATCH] First steps towards motion blur support. --- src/algorithm.rs | 4 +- src/bvh.rs | 138 ++++++++++++++++++++++++----------- src/main.rs | 2 +- src/surface/triangle_mesh.rs | 18 +++-- 4 files changed, 111 insertions(+), 51 deletions(-) diff --git a/src/algorithm.rs b/src/algorithm.rs index b1add19..8daafe2 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -8,8 +8,8 @@ use std; /// /// The predicate is executed precisely once on every element in /// the slice, and is allowed to modify the elements. -pub fn partition(slc: &mut [T], pred: F) -> usize - where F: Fn(&mut T) -> bool +pub fn partition(slc: &mut [T], mut pred: F) -> usize + where F: FnMut(&mut T) -> bool { // This version uses raw pointers and pointer arithmetic to squeeze more // performance out of the code. diff --git a/src/bvh.rs b/src/bvh.rs index 60974d4..1a16e7e 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +use lerp::lerp_slice; use bbox::BBox; use ray::Ray; use algorithm::partition; @@ -7,39 +8,64 @@ use algorithm::partition; #[derive(Debug)] pub struct BVH { nodes: Vec, + bounds: Vec, depth: usize, + bounds_cache: Vec, + bounds_temp: Vec, } #[derive(Debug)] enum BVHNode { Internal { - bounds: BBox, + bounds_range: (usize, usize), second_child_index: usize, split_axis: u8, }, Leaf { - bounds: BBox, + bounds_range: (usize, usize), object_range: (usize, usize), }, } impl BVH { - pub fn from_objects(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH - where F: Fn(&T) -> BBox + pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH + where F: Fn(&T, &mut Vec) { let mut bvh = BVH { nodes: Vec::new(), + bounds: Vec::new(), depth: 0, + bounds_cache: Vec::new(), + bounds_temp: Vec::new(), }; bvh.recursive_build(0, 0, objects_per_leaf, objects, &bounder); + bvh.bounds_cache.clear(); + bvh.bounds_temp.clear(); + bvh.bounds_cache.shrink_to_fit(); + bvh.bounds_temp.shrink_to_fit(); println!("BVH Depth: {}", bvh.depth); bvh } + fn acc_bounds(&mut self, objects1: &mut [T], bounder: F) + where F: Fn(&T, &mut Vec) + { + // TODO: merging of different length bounds + self.bounds_cache.clear(); + bounder(&objects1[0], &mut self.bounds_cache); + for obj in &objects1[1..] { + self.bounds_temp.clear(); + bounder(obj, &mut self.bounds_temp); + debug_assert!(self.bounds_cache.len() == self.bounds_temp.len()); + for i in 0..self.bounds_cache.len() { + self.bounds_cache[i] = self.bounds_cache[i] | self.bounds_temp[i]; + } + } + } fn recursive_build(&mut self, offset: usize, @@ -47,44 +73,60 @@ impl BVH { objects_per_leaf: usize, objects: &mut [T], bounder: &F) - -> usize - where F: Fn(&T) -> BBox + -> (usize, (usize, usize)) + where F: Fn(&T, &mut Vec) { + // fn acc_bounds2(objects2: &mut [T]) { + // self.bounds_cache2.clear(); + // bounder(&objects2[0], &mut self.bounds_cache2); + // for obj in &objects2[1..] { + // self.bounds_temp.clear(); + // bounder(obj, &mut self.bounds_temp); + // debug_assert!(self.bounds_cache2.len() == self.bounds_temp.len()); + // for i in 0..self.bounds_cache2.len() { + // self.bounds_cache2[i] = self.bounds_cache2[i] | self.bounds_temp[i]; + // } + // } + // } + let me = self.nodes.len(); if objects.len() == 0 { - return 0; + return (0, (0, 0)); } else if objects.len() <= objects_per_leaf { // Leaf node + self.acc_bounds(objects, bounder); + let bi = self.bounds.len(); + for b in self.bounds_cache.iter() { + self.bounds.push(*b); + } self.nodes.push(BVHNode::Leaf { - bounds: { - let mut bounds = bounder(&objects[0]); - for obj in &objects[1..] { - bounds = bounds | bounder(obj); - } - bounds - }, + bounds_range: (bi, self.bounds.len()), object_range: (offset, offset + objects.len()), }); if self.depth < depth { self.depth = depth; } + + return (me, (bi, self.bounds.len())); } else { // Not a leaf node self.nodes.push(BVHNode::Internal { - bounds: BBox::new(), + bounds_range: (0, 0), second_child_index: 0, split_axis: 0, }); // Determine which axis to split on let bounds = { - let mut bounds = BBox::new(); - for obj in objects.iter() { - bounds = bounds | bounder(obj); + let mut bb = BBox::new(); + for obj in &objects[..] { + self.bounds_cache.clear(); + bounder(obj, &mut self.bounds_cache); + bb = bb | lerp_slice(&self.bounds_cache[..], 0.5); } - bounds + bb }; let split_axis = { let x_ext = bounds.max[0] - bounds.min[0]; @@ -102,8 +144,10 @@ impl BVH { // Partition objects based on split let split_index = { - let mut split_i = partition(objects, |obj| { - let tb = bounder(obj); + let mut split_i = partition(&mut objects[..], |obj| { + self.bounds_cache.clear(); + bounder(obj, &mut self.bounds_cache); + let tb = lerp_slice(&self.bounds_cache[..], 0.5); let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5; centroid < split_pos }); @@ -115,26 +159,34 @@ impl BVH { }; // Create child nodes - self.recursive_build(offset, - depth + 1, - objects_per_leaf, - &mut objects[..split_index], - bounder); - let child2_index = self.recursive_build(offset + split_index, - depth + 1, - objects_per_leaf, - &mut objects[split_index..], - bounder); + let (_, c1_bounds) = self.recursive_build(offset, + depth + 1, + objects_per_leaf, + &mut objects[..split_index], + bounder); + let (c2_index, c2_bounds) = self.recursive_build(offset + split_index, + depth + 1, + objects_per_leaf, + &mut objects[split_index..], + bounder); + + // Determine bounds + // TODO: merging of different length bounds + let bi = self.bounds.len(); + for (i1, i2) in Iterator::zip(c1_bounds.0..c1_bounds.1, c2_bounds.0..c2_bounds.1) { + let bb = self.bounds[i1] | self.bounds[i2]; + self.bounds.push(bb); + } // Set node self.nodes[me] = BVHNode::Internal { - bounds: bounds, - second_child_index: child2_index, + bounds_range: (bi, self.bounds.len()), + second_child_index: c2_index, split_axis: split_axis as u8, }; - } - return me; + return (me, (bi, self.bounds.len())); + } } @@ -147,15 +199,16 @@ impl BVH { while stack_ptr > 0 { match self.nodes[i_stack[stack_ptr]] { - BVHNode::Internal { bounds, second_child_index, split_axis } => { - let part = partition(&mut rays[..ray_i_stack[stack_ptr]], - |r| bounds.intersect_ray(r)); + BVHNode::Internal { bounds_range: br, second_child_index, split_axis } => { + let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| { + lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r) + }); if part > 0 { i_stack[stack_ptr] += 1; i_stack[stack_ptr + 1] = second_child_index; ray_i_stack[stack_ptr] = part; ray_i_stack[stack_ptr + 1] = part; - if rays[0].dir[split_axis as usize] > 0.0 { + if rays[0].dir[split_axis as usize].is_sign_positive() { i_stack.swap(stack_ptr, stack_ptr + 1); } stack_ptr += 1; @@ -164,9 +217,10 @@ impl BVH { } } - BVHNode::Leaf { bounds, object_range } => { - let part = partition(&mut rays[..ray_i_stack[stack_ptr]], - |r| bounds.intersect_ray(r)); + BVHNode::Leaf { bounds_range: br, object_range } => { + let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| { + lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r) + }); if part > 0 { for obj in &objects[object_range.0..object_range.1] { obj_ray_test(obj, &mut rays[..part]); diff --git a/src/main.rs b/src/main.rs index c49179d..81918c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ fn main() { println!("Ray size: {} bytes", mem::size_of::()); // Generate a scene of triangles - let mesh = TriangleMesh::from_triangles({ + let mesh = TriangleMesh::from_triangles(1, { let mut triangles = Vec::new(); let xres = 32; let yres = 32; diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index a809527..9796ffd 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -9,22 +9,28 @@ use bvh::BVH; use super::{Surface, SurfaceIntersection}; pub struct TriangleMesh { + time_samples: usize, geo: Vec<(Point, Point, Point)>, accel: BVH, } impl TriangleMesh { - pub fn from_triangles(mut triangles: Vec<(Point, Point, Point)>) -> TriangleMesh { - let accel = BVH::from_objects(&mut triangles[..], 3, |tri| { + pub fn from_triangles(time_samples: usize, + mut triangles: Vec<(Point, Point, Point)>) + -> TriangleMesh { + assert!(triangles.len() % time_samples == 0); + // let mut indices: Vec = (0 .. (triangles.len() / time_samples)).collect(); + + let accel = BVH::from_objects(&mut triangles[..], 3, |tri, bounds| { + // for tri in &triangles[i..(i+time_samples)] { let minimum = tri.0.min(tri.1.min(tri.2)); let maximum = tri.0.max(tri.1.max(tri.2)); - BBox { - min: minimum, - max: maximum, - } + bounds.push(BBox::from_points(minimum, maximum)); + // } }); TriangleMesh { + time_samples: time_samples, geo: triangles, accel: accel, }