First steps towards motion blur support.
This commit is contained in:
parent
907d15f643
commit
c1b063411f
|
@ -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<T, F>(slc: &mut [T], pred: F) -> usize
|
||||
where F: Fn(&mut T) -> bool
|
||||
pub fn partition<T, F>(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.
|
||||
|
|
128
src/bvh.rs
128
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<BVHNode>,
|
||||
bounds: Vec<BBox>,
|
||||
depth: usize,
|
||||
bounds_cache: Vec<BBox>,
|
||||
bounds_temp: Vec<BBox>,
|
||||
}
|
||||
|
||||
#[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<T, F>(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<BBox>)
|
||||
{
|
||||
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<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,
|
||||
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<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();
|
||||
|
||||
if objects.len() == 0 {
|
||||
return 0;
|
||||
return (0, (0, 0));
|
||||
} else if objects.len() <= objects_per_leaf {
|
||||
// Leaf node
|
||||
self.nodes.push(BVHNode::Leaf {
|
||||
bounds: {
|
||||
let mut bounds = bounder(&objects[0]);
|
||||
for obj in &objects[1..] {
|
||||
bounds = bounds | bounder(obj);
|
||||
self.acc_bounds(objects, bounder);
|
||||
let bi = self.bounds.len();
|
||||
for b in self.bounds_cache.iter() {
|
||||
self.bounds.push(*b);
|
||||
}
|
||||
bounds
|
||||
},
|
||||
self.nodes.push(BVHNode::Leaf {
|
||||
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,
|
||||
let (_, c1_bounds) = self.recursive_build(offset,
|
||||
depth + 1,
|
||||
objects_per_leaf,
|
||||
&mut objects[..split_index],
|
||||
bounder);
|
||||
let child2_index = self.recursive_build(offset + split_index,
|
||||
let (c2_index, c2_bounds) = self.recursive_build(offset + split_index,
|
||||
depth + 1,
|
||||
objects_per_leaf,
|
||||
&mut objects[split_index..],
|
||||
bounder);
|
||||
|
||||
// Set node
|
||||
self.nodes[me] = BVHNode::Internal {
|
||||
bounds: bounds,
|
||||
second_child_index: child2_index,
|
||||
split_axis: split_axis as u8,
|
||||
};
|
||||
// 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);
|
||||
}
|
||||
|
||||
return me;
|
||||
// Set node
|
||||
self.nodes[me] = BVHNode::Internal {
|
||||
bounds_range: (bi, self.bounds.len()),
|
||||
second_child_index: c2_index,
|
||||
split_axis: split_axis as u8,
|
||||
};
|
||||
|
||||
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]);
|
||||
|
|
|
@ -74,7 +74,7 @@ fn main() {
|
|||
println!("Ray size: {} bytes", mem::size_of::<Ray>());
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -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<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 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,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user