diff --git a/src/bbox.rs b/src/bbox.rs index 88c3b6a..75ecea2 100644 --- a/src/bbox.rs +++ b/src/bbox.rs @@ -6,7 +6,7 @@ use std::iter::Iterator; use math::{Point, Matrix4x4}; use lerp::{lerp, lerp_slice, Lerp}; -use ray::Ray; +use ray::AccelRay; const BBOX_MAXT_ADJUST: f32 = 1.00000024; @@ -38,7 +38,7 @@ impl BBox { } // Returns whether the given ray intersects with the bbox. - pub fn intersect_ray(&self, ray: &Ray) -> bool { + pub fn intersect_accel_ray(&self, ray: &AccelRay) -> bool { // Calculate slab intersections let t1 = (self.min.co - ray.orig.co) * ray.dir_inv.co; let t2 = (self.max.co - ray.orig.co) * ray.dir_inv.co; diff --git a/src/bvh.rs b/src/bvh.rs index 4cc8287..6a6c32a 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -3,7 +3,7 @@ use lerp::lerp_slice; use bbox::BBox; use boundable::Boundable; -use ray::Ray; +use ray::{Ray, AccelRay}; use algorithm::partition; #[derive(Debug)] @@ -177,8 +177,8 @@ impl BVH { } - pub fn traverse(&self, rays: &mut [Ray], objects: &[T], mut obj_ray_test: F) - where F: FnMut(&T, &mut [Ray]) + pub fn traverse(&self, rays: &mut [AccelRay], objects: &[T], mut obj_ray_test: F) + where F: FnMut(&T, &mut [AccelRay]) { if self.nodes.len() == 0 { return; @@ -192,14 +192,14 @@ impl BVH { match self.nodes[i_stack[stack_ptr]] { 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) + lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_accel_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].is_sign_positive() { + if rays[0].dir_inv[split_axis as usize].is_sign_positive() { i_stack.swap(stack_ptr, stack_ptr + 1); } stack_ptr += 1; @@ -210,7 +210,7 @@ impl BVH { 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) + lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_accel_ray(r) }); if part > 0 { for obj in &objects[object_range.0..object_range.1] { diff --git a/src/main.rs b/src/main.rs index 96918c2..5c692d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ use std::fs::File; use docopt::Docopt; -use ray::Ray; +use ray::{Ray, AccelRay}; use parse::{parse_scene, DataTree}; // ---------------------------------------------------------------- @@ -91,7 +91,8 @@ fn main() { panic!() }; - println!("Ray size: {} bytes", mem::size_of::()); + println!("Ray size: {} bytes", mem::size_of::()); + println!("AccelRay size: {} bytes", mem::size_of::()); // Iterate through scenes and render them if let DataTree::Internal { ref children, .. } = dt { diff --git a/src/ray.rs b/src/ray.rs index 02bdb9f..108b142 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -9,10 +9,8 @@ use math::{Vector, Point, Matrix4x4}; pub struct Ray { pub orig: Point, pub dir: Vector, - pub dir_inv: Vector, pub max_t: f32, pub time: f32, - pub id: u32, pub flags: u32, } @@ -21,10 +19,8 @@ impl Ray { Ray { orig: orig, dir: dir, - dir_inv: Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / dir.co }, max_t: std::f32::INFINITY, time: time, - id: 0, flags: 0, } } @@ -32,16 +28,39 @@ impl Ray { pub fn transform(&mut self, mat: &Matrix4x4) { self.orig = self.orig * *mat; self.dir = self.dir * *mat; - self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / self.dir.co }; + } +} + + +#[derive(Debug, Copy, Clone)] +pub struct AccelRay { + pub orig: Point, + pub dir_inv: Vector, + pub max_t: f32, + pub time: f32, + pub flags: u32, + pub id: u32, +} + +impl AccelRay { + pub fn new(ray: &Ray, id: u32) -> AccelRay { + AccelRay { + orig: ray.orig, + dir_inv: Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / ray.dir.co }, + max_t: ray.max_t, + time: ray.time, + flags: ray.flags, + id: id, + } } pub fn update_from_world_ray(&mut self, wr: &Ray) { self.orig = wr.orig; - self.dir = wr.dir; + self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / wr.dir.co }; } pub fn update_from_xformed_world_ray(&mut self, wr: &Ray, mat: &Matrix4x4) { - self.update_from_world_ray(wr); - self.transform(mat); + self.orig = wr.orig * *mat; + self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / (wr.dir * *mat).co }; } } diff --git a/src/renderer.rs b/src/renderer.rs index e9675d4..70eec64 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -102,7 +102,6 @@ impl Renderer { halton::sample(1, offset + si as u32), halton::sample(2, offset + si as u32)) }; - ray.id = rays.len() as u32; rays.push(ray); pixel_mapping.push((x, y)) } @@ -120,7 +119,7 @@ impl Renderer { if let &surface::SurfaceIntersection::Hit { t: _, pos: _, nor: _, - space: _, + local_space: _, uv } = isect { col.0 += uv.0 / self.spp as f32; diff --git a/src/surface/mod.rs b/src/surface/mod.rs index a0993fd..78c1596 100644 --- a/src/surface/mod.rs +++ b/src/surface/mod.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; pub mod triangle_mesh; -use ray::Ray; +use ray::{Ray, AccelRay}; use math::{Point, Normal, Matrix4x4}; use boundable::Boundable; @@ -17,11 +17,15 @@ pub enum SurfaceIntersection { t: f32, pos: Point, nor: Normal, - space: Matrix4x4, + local_space: Matrix4x4, uv: (f32, f32), }, } pub trait Surface: Boundable + Debug + Sync { - fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]); + fn intersect_rays(&self, + accel_rays: &mut [AccelRay], + wrays: &[Ray], + isects: &mut [SurfaceIntersection], + space: &[Matrix4x4]); } diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index 1fcbb18..a302b8b 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] -use lerp::{lerp, lerp_slice_with}; +use lerp::{lerp, lerp_slice, lerp_slice_with}; use math::{Point, Normal, Matrix4x4}; -use ray::Ray; +use ray::{Ray, AccelRay}; use triangle; use bbox::BBox; use boundable::Boundable; @@ -59,22 +59,30 @@ impl Boundable for TriangleMesh { impl Surface for TriangleMesh { - fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) { - self.accel.traverse(&mut rays[..], &self.indices, |tri_i, rs| { + fn intersect_rays(&self, + accel_rays: &mut [AccelRay], + wrays: &[Ray], + isects: &mut [SurfaceIntersection], + space: &[Matrix4x4]) { + self.accel.traverse(&mut accel_rays[..], &self.indices, |tri_i, rs| { for r in rs { + let wr = &wrays[r.id as usize]; let tri = lerp_slice_with(&self.geo[*tri_i..(*tri_i + self.time_samples)], - r.time, + wr.time, |a, b, t| { (lerp(a.0, b.0, t), lerp(a.1, b.1, t), lerp(a.2, b.2, t)) }); - if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, tri) { + let mat_space = lerp_slice(space, wr.time); + let mat_inv = mat_space.inverse(); + let tri = (tri.0 * mat_inv, tri.1 * mat_inv, tri.2 * mat_inv); + if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(wr, tri) { if t < r.max_t { isects[r.id as usize] = SurfaceIntersection::Hit { t: t, - pos: r.orig + (r.dir * t), + pos: wr.orig + (wr.dir * t), nor: Normal::new(0.0, 0.0, 0.0), // TODO - space: Matrix4x4::new(), // TODO + local_space: mat_space, uv: (tri_u, tri_v), }; r.max_t = t; diff --git a/src/tracer.rs b/src/tracer.rs index 52a158a..b62edb5 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -4,12 +4,12 @@ use std::cell::UnsafeCell; use math::{Matrix4x4, multiply_matrix_slices}; use lerp::lerp_slice; use assembly::{Assembly, Object, InstanceType}; -use ray::Ray; +use ray::{Ray, AccelRay}; use surface::SurfaceIntersection; pub struct Tracer<'a> { root: &'a Assembly, - rays: UnsafeCell>, // Should only be used from trace(), not any other methods + rays: UnsafeCell>, // Should only be used from trace(), not any other methods xform_stack: TransformStack, isects: Vec, } @@ -30,7 +30,8 @@ impl<'a> Tracer<'a> { unsafe { (*rays_ptr).clear(); (*rays_ptr).reserve(wrays.len()); - (*rays_ptr).extend(wrays.iter()); + let mut ids = 0..(wrays.len() as u32); + (*rays_ptr).extend(wrays.iter().map(|wr| AccelRay::new(wr, ids.next().unwrap()))); } // Ready the isects @@ -55,8 +56,11 @@ impl<'a> Tracer<'a> { return &self.isects; } - fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) { - assembly.object_accel.traverse(&mut rays[..], &assembly.instances[..], |inst, rs| { + fn trace_assembly<'b>(&'b mut self, + assembly: &Assembly, + wrays: &[Ray], + accel_rays: &mut [AccelRay]) { + assembly.object_accel.traverse(&mut accel_rays[..], &assembly.instances[..], |inst, rs| { // Transform rays if needed if let Some((xstart, xend)) = inst.transform_indices { // Push transforms to stack @@ -106,10 +110,10 @@ impl<'a> Tracer<'a> { }); } - fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [Ray]) { + fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [AccelRay]) { match obj { &Object::Surface(ref surface) => { - surface.intersect_rays(rays, &mut self.isects); + surface.intersect_rays(rays, wrays, &mut self.isects, self.xform_stack.top()); } } }