From 53c9ff95347505f7abb5d7e299bae3c8fd4af5b4 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Thu, 31 Dec 2015 11:15:35 -0800 Subject: [PATCH] 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. --- src/bvh.rs | 74 +++++++++++++++++++++++++++-------------------------- src/main.rs | 24 ++++++++++++++--- 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/bvh.rs b/src/bvh.rs index 512372b..584bc22 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] +use std::marker; + use bbox::BBox; -use math::Point; use ray::Ray; -use triangle; use algorithm::partition; #[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)> { - if bvh.nodes.len() == 0 { - return None; +pub struct BVHTraverser<'a, T: 'a> { + bvh: &'a BVH<'a, T>, + 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]; - let mut stack_ptr: usize = 1; - let mut hit = false; - let mut u = 0.0; - let mut v = 0.0; - - while stack_ptr > 0 { - match bvh.nodes[i_stack[stack_ptr]] { - BVHNode::Internal { bounds, second_child_index } => { - if bounds.intersect_ray(ray) { - i_stack[stack_ptr] += 1; - i_stack[stack_ptr + 1] = second_child_index; - stack_ptr += 1; - } else { - stack_ptr -= 1; - } - } - - BVHNode::Leaf { bounds: _, object_index } => { - if let Some((t, tri_u, tri_v)) = - triangle::intersect_ray(ray, bvh.objects[object_index]) { - if t < ray.max_t { - hit = true; - ray.max_t = t; - u = tri_u; - v = tri_v; +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)> { + while self.stack_ptr > 0 { + match self.bvh.nodes[self.i_stack[self.stack_ptr]] { + BVHNode::Internal { bounds, second_child_index } => { + if bounds.intersect_ray(&(unsafe { *self.ray })) { + self.i_stack[self.stack_ptr] += 1; + self.i_stack[self.stack_ptr + 1] = second_child_index; + self.stack_ptr += 1; + } else { + self.stack_ptr -= 1; } } - stack_ptr -= 1; + BVHNode::Leaf { bounds: _, object_index } => { + self.stack_ptr -= 1; + unsafe { + return Some((&self.bvh.objects[object_index], &mut (*self.ray))); + } + } } } - } - if hit { - return Some((ray.max_t, u, v)); - } else { return None; } } diff --git a/src/main.rs b/src/main.rs index fc4ee07..b6f3735 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,8 +75,8 @@ fn main() { // Generate a scene of triangles let mut triangles = { let mut triangles = Vec::new(); - let xres = 512; - let yres = 512; + let xres = 16; + let yres = 16; let xinc = 512.0 / (xres as f32); let yinc = 512.0 / (yres as f32); for x in 0..xres { @@ -113,6 +113,7 @@ fn main() { let offset = hash_u32(((x as u32) << 16) ^ (y as u32), 0); const SAMPLES: usize = 16; for si in 0..SAMPLES { + // Generate ray let mut ray = Ray::new(Point::new(x as f32 + fast_logit(halton::sample(0, offset + si as u32), @@ -123,7 +124,23 @@ fn main() { 1.5), 0.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; g += v; b += (1.0 - u - v).max(0.0); @@ -136,6 +153,7 @@ fn main() { b += 0.1; } } + r *= 255.0 / SAMPLES as f32; g *= 255.0 / SAMPLES as f32; b *= 255.0 / SAMPLES as f32;