First steps towards motion blur support.

This commit is contained in:
Nathan Vegdahl 2016-01-03 21:21:46 -08:00
parent 907d15f643
commit c1b063411f
4 changed files with 111 additions and 51 deletions

View File

@ -8,8 +8,8 @@ use std;
/// ///
/// The predicate is executed precisely once on every element in /// The predicate is executed precisely once on every element in
/// the slice, and is allowed to modify the elements. /// the slice, and is allowed to modify the elements.
pub fn partition<T, F>(slc: &mut [T], pred: F) -> usize pub fn partition<T, F>(slc: &mut [T], mut pred: F) -> usize
where F: Fn(&mut T) -> bool where F: FnMut(&mut T) -> bool
{ {
// This version uses raw pointers and pointer arithmetic to squeeze more // This version uses raw pointers and pointer arithmetic to squeeze more
// performance out of the code. // performance out of the code.

View File

@ -1,5 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use lerp::lerp_slice;
use bbox::BBox; use bbox::BBox;
use ray::Ray; use ray::Ray;
use algorithm::partition; use algorithm::partition;
@ -7,39 +8,64 @@ use algorithm::partition;
#[derive(Debug)] #[derive(Debug)]
pub struct BVH { pub struct BVH {
nodes: Vec<BVHNode>, nodes: Vec<BVHNode>,
bounds: Vec<BBox>,
depth: usize, depth: usize,
bounds_cache: Vec<BBox>,
bounds_temp: Vec<BBox>,
} }
#[derive(Debug)] #[derive(Debug)]
enum BVHNode { enum BVHNode {
Internal { Internal {
bounds: BBox, bounds_range: (usize, usize),
second_child_index: usize, second_child_index: usize,
split_axis: u8, split_axis: u8,
}, },
Leaf { Leaf {
bounds: BBox, bounds_range: (usize, usize),
object_range: (usize, usize), object_range: (usize, usize),
}, },
} }
impl BVH { impl BVH {
pub fn from_objects<T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH
where F: Fn(&T) -> BBox where F: Fn(&T, &mut Vec<BBox>)
{ {
let mut bvh = BVH { let mut bvh = BVH {
nodes: Vec::new(), nodes: Vec::new(),
bounds: Vec::new(),
depth: 0, depth: 0,
bounds_cache: Vec::new(),
bounds_temp: Vec::new(),
}; };
bvh.recursive_build(0, 0, objects_per_leaf, objects, &bounder); 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); println!("BVH Depth: {}", bvh.depth);
bvh bvh
} }
fn acc_bounds<T, F>(&mut self, objects1: &mut [T], bounder: F)
where F: Fn(&T, &mut Vec<BBox>)
{
// 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<T, F>(&mut self, fn recursive_build<T, F>(&mut self,
offset: usize, offset: usize,
@ -47,44 +73,60 @@ impl BVH {
objects_per_leaf: usize, objects_per_leaf: usize,
objects: &mut [T], objects: &mut [T],
bounder: &F) bounder: &F)
-> usize -> (usize, (usize, usize))
where F: Fn(&T) -> BBox where F: Fn(&T, &mut Vec<BBox>)
{ {
// 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(); let me = self.nodes.len();
if objects.len() == 0 { if objects.len() == 0 {
return 0; return (0, (0, 0));
} else if objects.len() <= objects_per_leaf { } else if objects.len() <= objects_per_leaf {
// Leaf node // 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 { self.nodes.push(BVHNode::Leaf {
bounds: { bounds_range: (bi, self.bounds.len()),
let mut bounds = bounder(&objects[0]);
for obj in &objects[1..] {
bounds = bounds | bounder(obj);
}
bounds
},
object_range: (offset, offset + objects.len()), object_range: (offset, offset + objects.len()),
}); });
if self.depth < depth { if self.depth < depth {
self.depth = depth; self.depth = depth;
} }
return (me, (bi, self.bounds.len()));
} else { } else {
// Not a leaf node // Not a leaf node
self.nodes.push(BVHNode::Internal { self.nodes.push(BVHNode::Internal {
bounds: BBox::new(), bounds_range: (0, 0),
second_child_index: 0, second_child_index: 0,
split_axis: 0, split_axis: 0,
}); });
// Determine which axis to split on // Determine which axis to split on
let bounds = { let bounds = {
let mut bounds = BBox::new(); let mut bb = BBox::new();
for obj in objects.iter() { for obj in &objects[..] {
bounds = bounds | bounder(obj); 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 split_axis = {
let x_ext = bounds.max[0] - bounds.min[0]; let x_ext = bounds.max[0] - bounds.min[0];
@ -102,8 +144,10 @@ impl BVH {
// Partition objects based on split // Partition objects based on split
let split_index = { let split_index = {
let mut split_i = partition(objects, |obj| { let mut split_i = partition(&mut objects[..], |obj| {
let tb = bounder(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; let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5;
centroid < split_pos centroid < split_pos
}); });
@ -115,26 +159,34 @@ impl BVH {
}; };
// Create child nodes // Create child nodes
self.recursive_build(offset, let (_, c1_bounds) = self.recursive_build(offset,
depth + 1, depth + 1,
objects_per_leaf, objects_per_leaf,
&mut objects[..split_index], &mut objects[..split_index],
bounder); bounder);
let child2_index = self.recursive_build(offset + split_index, let (c2_index, c2_bounds) = self.recursive_build(offset + split_index,
depth + 1, depth + 1,
objects_per_leaf, objects_per_leaf,
&mut objects[split_index..], &mut objects[split_index..],
bounder); 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 // Set node
self.nodes[me] = BVHNode::Internal { self.nodes[me] = BVHNode::Internal {
bounds: bounds, bounds_range: (bi, self.bounds.len()),
second_child_index: child2_index, second_child_index: c2_index,
split_axis: split_axis as u8, split_axis: split_axis as u8,
}; };
}
return me; return (me, (bi, self.bounds.len()));
}
} }
@ -147,15 +199,16 @@ impl BVH {
while stack_ptr > 0 { while stack_ptr > 0 {
match self.nodes[i_stack[stack_ptr]] { match self.nodes[i_stack[stack_ptr]] {
BVHNode::Internal { bounds, second_child_index, split_axis } => { BVHNode::Internal { bounds_range: br, second_child_index, split_axis } => {
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|r| bounds.intersect_ray(r)); lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r)
});
if part > 0 { if part > 0 {
i_stack[stack_ptr] += 1; i_stack[stack_ptr] += 1;
i_stack[stack_ptr + 1] = second_child_index; i_stack[stack_ptr + 1] = second_child_index;
ray_i_stack[stack_ptr] = part; ray_i_stack[stack_ptr] = part;
ray_i_stack[stack_ptr + 1] = 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); i_stack.swap(stack_ptr, stack_ptr + 1);
} }
stack_ptr += 1; stack_ptr += 1;
@ -164,9 +217,10 @@ impl BVH {
} }
} }
BVHNode::Leaf { bounds, object_range } => { BVHNode::Leaf { bounds_range: br, object_range } => {
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|r| bounds.intersect_ray(r)); lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r)
});
if part > 0 { if part > 0 {
for obj in &objects[object_range.0..object_range.1] { for obj in &objects[object_range.0..object_range.1] {
obj_ray_test(obj, &mut rays[..part]); obj_ray_test(obj, &mut rays[..part]);

View File

@ -74,7 +74,7 @@ fn main() {
println!("Ray size: {} bytes", mem::size_of::<Ray>()); println!("Ray size: {} bytes", mem::size_of::<Ray>());
// Generate a scene of triangles // Generate a scene of triangles
let mesh = TriangleMesh::from_triangles({ let mesh = TriangleMesh::from_triangles(1, {
let mut triangles = Vec::new(); let mut triangles = Vec::new();
let xres = 32; let xres = 32;
let yres = 32; let yres = 32;

View File

@ -9,22 +9,28 @@ use bvh::BVH;
use super::{Surface, SurfaceIntersection}; use super::{Surface, SurfaceIntersection};
pub struct TriangleMesh { pub struct TriangleMesh {
time_samples: usize,
geo: Vec<(Point, Point, Point)>, geo: Vec<(Point, Point, Point)>,
accel: BVH, accel: BVH,
} }
impl TriangleMesh { impl TriangleMesh {
pub fn from_triangles(mut triangles: Vec<(Point, Point, Point)>) -> TriangleMesh { pub fn from_triangles(time_samples: usize,
let accel = BVH::from_objects(&mut triangles[..], 3, |tri| { mut triangles: Vec<(Point, Point, Point)>)
-> TriangleMesh {
assert!(triangles.len() % time_samples == 0);
// let mut indices: Vec<usize> = (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 minimum = tri.0.min(tri.1.min(tri.2));
let maximum = tri.0.max(tri.1.max(tri.2)); let maximum = tri.0.max(tri.1.max(tri.2));
BBox { bounds.push(BBox::from_points(minimum, maximum));
min: minimum, // }
max: maximum,
}
}); });
TriangleMesh { TriangleMesh {
time_samples: time_samples,
geo: triangles, geo: triangles,
accel: accel, accel: accel,
} }