From e77d5b75766dacf0316dfda7627baa20c20dca18 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 30 Jul 2017 16:56:28 -0700 Subject: [PATCH] Refactored triangle meshes in preparation for custom normals. --- src/parse/psy_mesh_surface.rs | 46 +++++++--------- src/surface/triangle_mesh.rs | 98 +++++++++++++++++++++++++---------- 2 files changed, 91 insertions(+), 53 deletions(-) diff --git a/src/parse/psy_mesh_surface.rs b/src/parse/psy_mesh_surface.rs index 1e16374..c47bc74 100644 --- a/src/parse/psy_mesh_surface.rs +++ b/src/parse/psy_mesh_surface.rs @@ -25,7 +25,7 @@ pub fn parse_mesh_surface<'a>( arena: &'a MemArena, tree: &'a DataTree, ) -> Result, PsyParseError> { - let mut verts = Vec::new(); + let mut verts = Vec::new(); // Vec of vecs, one for each time sample let mut face_vert_counts = Vec::new(); let mut face_vert_indices = Vec::new(); @@ -33,30 +33,25 @@ pub fn parse_mesh_surface<'a>( // and other validation. // Get verts - let mut time_samples = 0; - let mut first_vert_count = None; for (_, text, _) in tree.iter_leaf_children_with_type("Vertices") { let mut raw_text = text.trim().as_bytes(); // Collect verts for this time sample - let mut vert_count = 0; + let mut tverts = Vec::new(); while let IResult::Done(remaining, vert) = closure!(tuple!(ws_f32, ws_f32, ws_f32))(raw_text) { raw_text = remaining; - verts.push(Point::new(vert.0, vert.1, vert.2)); - vert_count += 1; + tverts.push(Point::new(vert.0, vert.1, vert.2)); } + verts.push(tverts); + } - // Make sure all time samples have same vert count - if let Some(fvc) = first_vert_count { - assert_eq!(vert_count, fvc); - } else { - first_vert_count = Some(vert_count); - } - - time_samples += 1; + // Make sure all time samples have same vert count + let vert_count = verts[0].len(); + for vs in &verts { + assert_eq!(vert_count, vs.len()); } // Get face vert counts @@ -82,23 +77,18 @@ pub fn parse_mesh_surface<'a>( } // Build triangle mesh - let mut triangles = Vec::new(); - let vert_count = first_vert_count.unwrap(); + let mut tri_vert_indices = Vec::new(); let mut ii = 0; for fvc in &face_vert_counts { if *fvc >= 3 { // Store the polygon, split up into triangles if >3 verts let v1 = ii; for vi in 0..(fvc - 2) { - // Store all the time samples of each triangle contiguously - for time_sample in 0..time_samples { - let start_vi = vert_count * time_sample; - triangles.push(( - verts[start_vi + face_vert_indices[v1]], - verts[start_vi + face_vert_indices[v1 + vi + 1]], - verts[start_vi + face_vert_indices[v1 + vi + 2]], - )); - } + tri_vert_indices.push(( + face_vert_indices[v1], + face_vert_indices[v1 + vi + 1], + face_vert_indices[v1 + vi + 2], + )); } } else { // TODO: proper error @@ -108,5 +98,9 @@ pub fn parse_mesh_surface<'a>( ii += *fvc; } - Ok(TriangleMesh::from_triangles(arena, time_samples, triangles)) + Ok(TriangleMesh::from_verts_and_indices( + arena, + verts, + tri_vert_indices, + )) } diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index 50bafcb..547d918 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -7,7 +7,7 @@ use bbox::BBox; use boundable::Boundable; use color::XYZ; use fp_utils::fp_gamma; -use lerp::{lerp, lerp_slice, lerp_slice_with}; +use lerp::lerp_slice; use math::{Point, Matrix4x4, cross}; use ray::{Ray, AccelRay}; use shading::surface_closure::{SurfaceClosureUnion, GTRClosure, LambertClosure}; @@ -18,42 +18,71 @@ use super::triangle; #[derive(Copy, Clone, Debug)] pub struct TriangleMesh<'a> { - time_samples: usize, - geo: &'a [(Point, Point, Point)], - indices: &'a [usize], + time_sample_count: usize, + vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously + indices: &'a [(u32, u32, u32, u32)], // (v0_idx, v1_idx, v2_idx, original_tri_idx) accel: BVH4<'a>, } impl<'a> TriangleMesh<'a> { - pub fn from_triangles<'b>( + pub fn from_verts_and_indices<'b>( arena: &'b MemArena, - time_samples: usize, - triangles: Vec<(Point, Point, Point)>, + verts: Vec>, + tri_indices: Vec<(usize, usize, usize)>, ) -> TriangleMesh<'b> { - assert_eq!(triangles.len() % time_samples, 0); + let vert_count = verts[0].len(); + let time_sample_count = verts.len(); - let mut indices: Vec = (0..(triangles.len() / time_samples)) - .map(|n| n * time_samples) - .collect(); + // Copy verts over to a contiguous area of memory, reorganizing them + // so that each vertices' time samples are contiguous in memory. + let vertices = { + let mut vertices = + unsafe { arena.alloc_array_uninitialized(vert_count * time_sample_count) }; + for vi in 0..vert_count { + for ti in 0..time_sample_count { + vertices[(vi * time_sample_count) + ti] = verts[ti][vi]; + } + } + + vertices + }; + + // Copy triangle vertex indices over, appending the triangle index itself to the tuple + let mut indices = { + let mut indices = unsafe { arena.alloc_array_uninitialized(tri_indices.len()) }; + for (i, tri_i) in tri_indices.iter().enumerate() { + indices[i] = (tri_i.0 as u32, tri_i.2 as u32, tri_i.1 as u32, i as u32); + } + indices + }; + + // Create bounds array for use during BVH construction let bounds = { - let mut bounds = Vec::new(); - for tri in &triangles { - 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 mut bounds = Vec::with_capacity(indices.len() * time_sample_count); + for tri in &tri_indices { + for ti in 0..time_sample_count { + let p0 = verts[ti][tri.0]; + let p1 = verts[ti][tri.1]; + let p2 = verts[ti][tri.2]; + let minimum = p0.min(p1.min(p2)); + let maximum = p0.max(p1.max(p2)); + bounds.push(BBox::from_points(minimum, maximum)); + } } bounds }; - let accel = BVH4::from_objects(arena, &mut indices[..], 3, |tri_i| { - &bounds[*tri_i..(*tri_i + time_samples)] + // Build BVH + let accel = BVH4::from_objects(arena, &mut indices[..], 3, |tri| { + &bounds[(tri.3 as usize * time_sample_count).. + ((tri.3 as usize + 1) * time_sample_count)] }); TriangleMesh { - time_samples: time_samples, - geo: arena.copy_slice(&triangles), - indices: arena.copy_slice(&indices), + time_sample_count: time_sample_count, + vertices: vertices, + indices: indices, accel: accel, } } @@ -83,16 +112,31 @@ impl<'a> Surface for TriangleMesh<'a> { self.accel .traverse( - &mut accel_rays[..], self.indices, |tri_i, rs| { + &mut accel_rays[..], self.indices, |tri_indices, rs| { for r in rs { let wr = &wrays[r.id as usize]; // Get triangle - let tri = lerp_slice_with( - &self.geo[*tri_i..(*tri_i + self.time_samples)], - wr.time, - |a, b, t| (lerp(a.0, b.0, t), lerp(a.1, b.1, t), lerp(a.2, b.2, t)), - ); + let tri = { + let p0_slice = &self.vertices[ + (tri_indices.0 as usize * self.time_sample_count).. + ((tri_indices.0 as usize + 1) * self.time_sample_count) + ]; + let p1_slice = &self.vertices[ + (tri_indices.1 as usize * self.time_sample_count).. + ((tri_indices.1 as usize + 1) * self.time_sample_count) + ]; + let p2_slice = &self.vertices[ + (tri_indices.2 as usize * self.time_sample_count).. + ((tri_indices.2 as usize + 1) * self.time_sample_count) + ]; + + let p0 = lerp_slice(p0_slice, wr.time); + let p1 = lerp_slice(p1_slice, wr.time); + let p2 = lerp_slice(p2_slice, wr.time); + + (p0, p1, p2) + }; // Transform triangle as necessary, and get transform // space.