Replaced BVHTraverser with a method that takes a closure.

This is not only simpler conceptually, but also turns out to have
better performance.
This commit is contained in:
Nathan Vegdahl 2016-01-02 13:10:06 -08:00
parent 5278675fb7
commit 9b5e6ad23d
2 changed files with 29 additions and 55 deletions

View File

@ -1,8 +1,5 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::marker;
use std::slice;
use bbox::BBox; use bbox::BBox;
use ray::Ray; use ray::Ray;
use algorithm::partition; use algorithm::partition;
@ -139,64 +136,43 @@ impl<'a, T> BVH<'a, T> {
return me; return me;
} }
}
pub struct BVHTraverser<'a, T: 'a> { pub fn traverse<F>(&self, rays: &mut [Ray], mut obj_ray_test: F)
bvh: &'a BVH<'a, T>, where F: FnMut(&T, &mut [Ray])
rays: (*mut Ray, usize), {
_ray_marker: marker::PhantomData<&'a mut [Ray]>, let mut i_stack = [0; 65];
i_stack: [usize; 65], let mut ray_i_stack = [rays.len(); 65];
ray_i_stack: [usize; 65], let mut stack_ptr = 1;
stack_ptr: usize,
}
impl<'a, T> BVHTraverser<'a, T> { while stack_ptr > 0 {
pub fn from_bvh_and_ray(bvh: &'a BVH<'a, T>, rays: &'a mut [Ray]) -> BVHTraverser<'a, T> { match self.nodes[i_stack[stack_ptr]] {
BVHTraverser {
bvh: bvh,
rays: (&mut rays[0] as *mut Ray, rays.len()),
_ray_marker: marker::PhantomData,
i_stack: [0; 65],
ray_i_stack: [rays.len(); 65],
stack_ptr: 1,
}
}
}
impl<'a, T> Iterator for BVHTraverser<'a, T> {
type Item = (&'a [T], &'a mut [Ray]);
fn next(&mut self) -> Option<(&'a [T], &'a mut [Ray])> {
let rays = unsafe { slice::from_raw_parts_mut(self.rays.0, self.rays.1) };
while self.stack_ptr > 0 {
match self.bvh.nodes[self.i_stack[self.stack_ptr]] {
BVHNode::Internal { bounds, second_child_index } => { BVHNode::Internal { bounds, second_child_index } => {
let part = partition(&mut rays[..self.ray_i_stack[self.stack_ptr]], let part = partition(&mut rays[..ray_i_stack[stack_ptr]],
|r| bounds.intersect_ray(r)); |r| bounds.intersect_ray(r));
if part > 0 { if part > 0 {
self.i_stack[self.stack_ptr] += 1; i_stack[stack_ptr] += 1;
self.i_stack[self.stack_ptr + 1] = second_child_index; i_stack[stack_ptr + 1] = second_child_index;
self.ray_i_stack[self.stack_ptr] = part; ray_i_stack[stack_ptr] = part;
self.ray_i_stack[self.stack_ptr + 1] = part; ray_i_stack[stack_ptr + 1] = part;
self.stack_ptr += 1; stack_ptr += 1;
} else { } else {
self.stack_ptr -= 1; stack_ptr -= 1;
} }
} }
BVHNode::Leaf { bounds, object_range } => { BVHNode::Leaf { bounds, object_range } => {
// let part = self.ray_i_stack[self.stack_ptr]; let part = partition(&mut rays[..ray_i_stack[stack_ptr]],
let part = partition(&mut rays[..self.ray_i_stack[self.stack_ptr]],
|r| bounds.intersect_ray(r)); |r| bounds.intersect_ray(r));
self.stack_ptr -= 1;
if part > 0 { if part > 0 {
return Some((&self.bvh.objects[object_range.0..object_range.1], for obj in &self.objects[object_range.0..object_range.1] {
&mut rays[..part])); obj_ray_test(obj, &mut rays[..part]);
}
}
} }
} }
return None; stack_ptr -= 1;
}
}
}
} }
} }

View File

@ -143,10 +143,9 @@ fn main() {
isects.push((false, 0.0, 0.0)); isects.push((false, 0.0, 0.0));
} }
// Test ray against scene // Test rays against scene
for (tris, rs) in bvh::BVHTraverser::from_bvh_and_ray(&scene, &mut rays[..]) { scene.traverse(&mut rays, |tri, rs| {
for r in rs.iter_mut() { for r in rs {
for tri in tris.iter() {
if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, *tri) { if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, *tri) {
if t < r.max_t { if t < r.max_t {
isects[r.id as usize] = (true, tri_u, tri_v); isects[r.id as usize] = (true, tri_u, tri_v);
@ -154,8 +153,7 @@ fn main() {
} }
} }
} }
} });
}
// Calculate color based on ray hits // Calculate color based on ray hits
let mut r = 0.0; let mut r = 0.0;