diff --git a/src/assembly.rs b/src/assembly.rs index 1a449ef..62efe32 100644 --- a/src/assembly.rs +++ b/src/assembly.rs @@ -9,19 +9,19 @@ use ray::Ray; #[derive(Debug)] pub struct Assembly { // Instance list - instances: Vec, - xforms: Vec, + pub instances: Vec, + pub xforms: Vec, // Object list - objects: Vec, + pub objects: Vec, object_map: HashMap, // map Name -> Index // Assembly list - assemblies: Vec, + pub assemblies: Vec, assembly_map: HashMap, // map Name -> Index // Object accel - object_accel: BVH, + pub object_accel: BVH, } impl Assembly { @@ -37,17 +37,6 @@ impl Assembly { } } - // TODO: this is just temporary. Remove this and move tracing functionality - // into the tracer. - pub fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) { - for obj in self.objects.iter() { - match obj { - &Object::Surface(ref surface) => { - surface.intersect_rays(rays, isects); - } - } - } - } pub fn add_object(&mut self, name: &str, obj: Object) { @@ -64,7 +53,7 @@ pub enum Object { #[derive(Debug, Copy, Clone)] -enum Instance { +pub enum Instance { Object { data_index: usize, transform_indices: (usize, usize), diff --git a/src/renderer.rs b/src/renderer.rs index 27435d0..3dd37f9 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -2,6 +2,7 @@ use std::path::Path; +use tracer::Tracer; use camera::Camera; use halton; use math::fast_logit; @@ -21,7 +22,7 @@ pub struct Renderer { impl Renderer { pub fn render(&self) { let mut rays = Vec::new(); - let mut isects = Vec::new(); + let mut tracer = Tracer::from_assembly(&self.scene.root); let mut img = Image::new(self.resolution.0, self.resolution.1); // Render image of ray-traced triangle @@ -34,7 +35,6 @@ impl Renderer { // Generate rays rays.clear(); - isects.clear(); for si in 0..self.spp { let mut ray = { let filter_x = fast_logit(halton::sample(3, offset + si as u32), 1.5); @@ -47,11 +47,10 @@ impl Renderer { }; ray.id = si as u32; rays.push(ray); - isects.push(surface::SurfaceIntersection::Miss); } // Test rays against scene - self.scene.root.intersect_rays(&mut rays, &mut isects); + let isects = tracer.trace(&rays); // Calculate color based on ray hits let mut r = 0.0; diff --git a/src/surface/mod.rs b/src/surface/mod.rs index f38e5e7..bb0abdc 100644 --- a/src/surface/mod.rs +++ b/src/surface/mod.rs @@ -8,7 +8,7 @@ use ray::Ray; use math::{Point, Normal, Matrix4x4}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum SurfaceIntersection { Miss, Occlude, diff --git a/src/tracer.rs b/src/tracer.rs index 7c5252b..956b5fd 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -1,10 +1,63 @@ +use std::iter; +use std::slice; + use math::Matrix4x4; +use assembly::{Assembly, Object}; use ray::Ray; use surface::SurfaceIntersection; pub struct Tracer<'a> { + root: &'a Assembly, + rays: Vec, // Should only be used from trace(), not any other methods xform_stack: Vec, - world_rays: &'a [Ray], - intersections: &'a mut [SurfaceIntersection], - rays: Vec, + isects: Vec, +} + +impl<'a> Tracer<'a> { + pub fn from_assembly(assembly: &'a Assembly) -> Tracer<'a> { + Tracer { + root: assembly, + xform_stack: Vec::new(), + rays: Vec::new(), + isects: Vec::new(), + } + } + + pub fn trace<'b>(&'b mut self, wrays: &[Ray]) -> &'b [SurfaceIntersection] { + // Ready the rays + self.rays.clear(); + self.rays.reserve(wrays.len()); + self.rays.extend(wrays.iter()); + + // Ready the isects + self.isects.clear(); + self.isects.reserve(wrays.len()); + self.isects.extend(iter::repeat(SurfaceIntersection::Miss).take(wrays.len())); + + // Start tracing + let ray_refs = unsafe { + // IMPORTANT NOTE: + // We're creating an unsafe non-lifetime-bound slice of self.rays + // here so that we can pass it to trace_assembly() without + // conflicting with self. + // Because of this, it is absolutely CRITICAL that self.rays + // NOT be used in any other methods. The rays should only be + // accessed in other methods via the mutable slice passed directly + // to them in their function parameters. + slice::from_raw_parts_mut(self.rays.as_mut_ptr(), self.rays.len()) + }; + self.trace_assembly(self.root, wrays, ray_refs); + + return &self.isects; + } + + fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) { + for obj in assembly.objects.iter() { + match obj { + &Object::Surface(ref surface) => { + surface.intersect_rays(rays, &mut self.isects); + } + } + } + } } diff --git a/todo.txt b/todo.txt index edd8cbc..3d9653a 100644 --- a/todo.txt +++ b/todo.txt @@ -1 +1,4 @@ -- Implement a basic camera. \ No newline at end of file +- Implement a Tracer to handle ray tracing responsibilities, with hierarchical + instancing, etc. +- Basic scene parsing with triangle meshes. +- Unit tests for scene parsing. \ No newline at end of file