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)]
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,
}
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;
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,
}
}
}
while stack_ptr > 0 {
match bvh.nodes[i_stack[stack_ptr]] {
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(ray) {
i_stack[stack_ptr] += 1;
i_stack[stack_ptr + 1] = second_child_index;
stack_ptr += 1;
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 {
stack_ptr -= 1;
self.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;
self.stack_ptr -= 1;
unsafe {
return Some((&self.bvh.objects[object_index], &mut (*self.ray)));
}
}
stack_ptr -= 1;
}
}
}
if hit {
return Some((ray.max_t, u, v));
} else {
return None;
}
}

View File

@ -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;