From 655c16542de4bdcaaef9b976b354f357fde3f195 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Tue, 5 Jan 2016 07:44:37 -0800 Subject: [PATCH] Implemented basic deformation motion blur for triangles. Not 100% happy with the interface of the BVH building yet, and there are still some missing features as well. But it's a start! --- src/lerp.rs | 22 +++++++++++++++++++++- src/main.rs | 8 ++++---- src/surface/triangle_mesh.rs | 32 ++++++++++++++++++++++---------- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/lerp.rs b/src/lerp.rs index 87c6067..fdd8e26 100644 --- a/src/lerp.rs +++ b/src/lerp.rs @@ -23,7 +23,7 @@ pub fn lerp_slice(s: &[T], alpha: f32) -> T { debug_assert!(alpha >= 0.0); debug_assert!(alpha <= 1.0); - if alpha == 1.0 || s.len() == 1 { + if s.len() == 1 || alpha == 1.0 { return *s.last().unwrap(); } else { let tmp = alpha * ((s.len() - 1) as f32); @@ -35,6 +35,26 @@ pub fn lerp_slice(s: &[T], alpha: f32) -> T { } } +pub fn lerp_slice_with(s: &[T], alpha: f32, f: F) -> T + where T: Copy, + F: Fn(T, T, f32) -> T +{ + debug_assert!(s.len() > 0); + debug_assert!(alpha >= 0.0); + debug_assert!(alpha <= 1.0); + + if s.len() == 1 || alpha == 1.0 { + return *s.last().unwrap(); + } else { + let tmp = alpha * ((s.len() - 1) as f32); + let i1 = tmp as usize; + let i2 = i1 + 1; + let alpha2 = tmp - (i1 as f32); + + return f(s[i1], s[i2], alpha2); + } +} + impl Lerp for f32 { fn lerp(self, other: f32, alpha: f32) -> f32 { diff --git a/src/main.rs b/src/main.rs index 81918c4..4ba409c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ fn main() { println!("Ray size: {} bytes", mem::size_of::()); // Generate a scene of triangles - let mesh = TriangleMesh::from_triangles(1, { + let mesh = TriangleMesh::from_triangles(2, { let mut triangles = Vec::new(); let xres = 32; let yres = 32; @@ -92,9 +92,9 @@ fn main() { triangles.push((Point::new(cx, cy, cz + 1.0), Point::new(cx + xinc, cy, cz + 1.1), Point::new(cx, cy + yinc, cz + 1.2))); - triangles.push((Point::new(cx + xinc, cy + yinc, cz + 1.0), - Point::new(cx, cy + yinc, cz + 1.1), - Point::new(cx + xinc, cy, cz + 1.2))); + triangles.push((Point::new(cx + 25.0, cy, cz + 1.0), + Point::new(cx + 25.0 + xinc, cy, cz + 1.1), + Point::new(cx + 25.0, cy + yinc, cz + 1.2))); } } triangles diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index 9796ffd..6106499 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +use lerp::{lerp, lerp_slice_with}; use math::{Point, Normal, Matrix4x4}; use ray::Ray; use triangle; @@ -11,27 +12,31 @@ use super::{Surface, SurfaceIntersection}; pub struct TriangleMesh { time_samples: usize, geo: Vec<(Point, Point, Point)>, + indices: Vec, accel: BVH, } impl TriangleMesh { pub fn from_triangles(time_samples: usize, - mut triangles: Vec<(Point, Point, Point)>) + triangles: Vec<(Point, Point, Point)>) -> TriangleMesh { assert!(triangles.len() % time_samples == 0); - // let mut indices: Vec = (0 .. (triangles.len() / time_samples)).collect(); + let mut indices: Vec = (0..(triangles.len() / time_samples)) + .map(|n| n * time_samples) + .collect(); - let accel = BVH::from_objects(&mut triangles[..], 3, |tri, bounds| { - // for tri in &triangles[i..(i+time_samples)] { - let minimum = tri.0.min(tri.1.min(tri.2)); - let maximum = tri.0.max(tri.1.max(tri.2)); - bounds.push(BBox::from_points(minimum, maximum)); - // } + let accel = BVH::from_objects(&mut indices[..], 3, |tri_i, bounds| { + for tri in &triangles[*tri_i..(*tri_i + time_samples)] { + let minimum = tri.0.min(tri.1.min(tri.2)); + let maximum = tri.0.max(tri.1.max(tri.2)); + bounds.push(BBox::from_points(minimum, maximum)); + } }); TriangleMesh { time_samples: time_samples, geo: triangles, + indices: indices, accel: accel, } } @@ -40,9 +45,16 @@ impl TriangleMesh { impl Surface for TriangleMesh { fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) { - self.accel.traverse(&mut rays[..], &self.geo, |tri, rs| { + self.accel.traverse(&mut rays[..], &self.indices, |tri_i, rs| { for r in rs { - if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, *tri) { + let tri = lerp_slice_with(&self.geo[*tri_i..(*tri_i + self.time_samples)], + r.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) { if t < r.max_t { isects[r.id as usize] = SurfaceIntersection::Hit { t: t,