Made a BVHTraverser iterator that traverses a BVH with a ray.

It yields the objects that the ray needs to be tested against.
Thus it is the responsibility of the code using the iterator
to actually do the object-level ray tests and update the ray's
max_t etc. accordingly.

This keeps all of the BVH-related code generic with respect to
what kind of object/data the BVH actually contains, which means
the same BVH code can be used for both scene-level and
triangle-level data.
This commit is contained in:
Nathan Vegdahl 2015-12-31 11:15:35 -08:00
parent 1c660dda13
commit 53c9ff9534
2 changed files with 59 additions and 39 deletions

View File

@ -1,9 +1,9 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::marker;
use bbox::BBox; use bbox::BBox;
use math::Point;
use ray::Ray; use ray::Ray;
use triangle;
use algorithm::partition; use algorithm::partition;
#[derive(Debug)] #[derive(Debug)]
@ -129,48 +129,50 @@ impl<'a, T> BVH<'a, T> {
} }
pub fn intersect_bvh(bvh: &BVH<(Point, Point, Point)>, ray: &mut Ray) -> Option<(f32, f32, f32)> { pub struct BVHTraverser<'a, T: 'a> {
if bvh.nodes.len() == 0 { bvh: &'a BVH<'a, T>,
return None; ray: *mut Ray,
_ray_marker: marker::PhantomData<&'a mut Ray>,
i_stack: [usize; 65],
stack_ptr: usize,
}
impl<'a, T> BVHTraverser<'a, T> {
pub fn from_bvh_and_ray(bvh: &'a BVH<'a, T>, ray: &'a mut Ray) -> BVHTraverser<'a, T> {
BVHTraverser {
bvh: bvh,
ray: ray as *mut Ray,
_ray_marker: marker::PhantomData,
i_stack: [0; 65],
stack_ptr: 1,
} }
}
}
let mut i_stack = [0; 65]; impl<'a, T> Iterator for BVHTraverser<'a, T> {
let mut stack_ptr: usize = 1; type Item = (&'a T, &'a mut Ray);
let mut hit = false; fn next(&mut self) -> Option<(&'a T, &'a mut Ray)> {
let mut u = 0.0; while self.stack_ptr > 0 {
let mut v = 0.0; match self.bvh.nodes[self.i_stack[self.stack_ptr]] {
while stack_ptr > 0 {
match bvh.nodes[i_stack[stack_ptr]] {
BVHNode::Internal { bounds, second_child_index } => { BVHNode::Internal { bounds, second_child_index } => {
if bounds.intersect_ray(ray) { if bounds.intersect_ray(&(unsafe { *self.ray })) {
i_stack[stack_ptr] += 1; self.i_stack[self.stack_ptr] += 1;
i_stack[stack_ptr + 1] = second_child_index; self.i_stack[self.stack_ptr + 1] = second_child_index;
stack_ptr += 1; self.stack_ptr += 1;
} else { } else {
stack_ptr -= 1; self.stack_ptr -= 1;
} }
} }
BVHNode::Leaf { bounds: _, object_index } => { BVHNode::Leaf { bounds: _, object_index } => {
if let Some((t, tri_u, tri_v)) = self.stack_ptr -= 1;
triangle::intersect_ray(ray, bvh.objects[object_index]) { unsafe {
if t < ray.max_t { return Some((&self.bvh.objects[object_index], &mut (*self.ray)));
hit = true;
ray.max_t = t;
u = tri_u;
v = tri_v;
} }
} }
stack_ptr -= 1;
}
} }
} }
if hit {
return Some((ray.max_t, u, v));
} else {
return None; return None;
} }
} }

View File

@ -75,8 +75,8 @@ fn main() {
// Generate a scene of triangles // Generate a scene of triangles
let mut triangles = { let mut triangles = {
let mut triangles = Vec::new(); let mut triangles = Vec::new();
let xres = 512; let xres = 16;
let yres = 512; let yres = 16;
let xinc = 512.0 / (xres as f32); let xinc = 512.0 / (xres as f32);
let yinc = 512.0 / (yres as f32); let yinc = 512.0 / (yres as f32);
for x in 0..xres { for x in 0..xres {
@ -113,6 +113,7 @@ fn main() {
let offset = hash_u32(((x as u32) << 16) ^ (y as u32), 0); let offset = hash_u32(((x as u32) << 16) ^ (y as u32), 0);
const SAMPLES: usize = 16; const SAMPLES: usize = 16;
for si in 0..SAMPLES { for si in 0..SAMPLES {
// Generate ray
let mut ray = Ray::new(Point::new(x as f32 + let mut ray = Ray::new(Point::new(x as f32 +
fast_logit(halton::sample(0, fast_logit(halton::sample(0,
offset + si as u32), offset + si as u32),
@ -123,7 +124,23 @@ fn main() {
1.5), 1.5),
0.0), 0.0),
Vector::new(0.0, 0.0, 1.0)); Vector::new(0.0, 0.0, 1.0));
if let Some((_, u, v)) = bvh::intersect_bvh(&scene, &mut ray) {
// Test ray against scene
let (mut u, mut v) = (0.0, 0.0);
let mut hit = false;
for (tri, r) in bvh::BVHTraverser::from_bvh_and_ray(&scene, &mut ray) {
if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, *tri) {
if t < r.max_t {
hit = true;
r.max_t = t;
u = tri_u;
v = tri_v;
}
}
}
// Update color based on ray hit
if hit {
r += u; r += u;
g += v; g += v;
b += (1.0 - u - v).max(0.0); b += (1.0 - u - v).max(0.0);
@ -136,6 +153,7 @@ fn main() {
b += 0.1; b += 0.1;
} }
} }
r *= 255.0 / SAMPLES as f32; r *= 255.0 / SAMPLES as f32;
g *= 255.0 / SAMPLES as f32; g *= 255.0 / SAMPLES as f32;
b *= 255.0 / SAMPLES as f32; b *= 255.0 / SAMPLES as f32;