Refactored triangle meshes in preparation for custom normals.

This commit is contained in:
Nathan Vegdahl 2017-07-30 16:56:28 -07:00
parent c75c154e46
commit e77d5b7576
2 changed files with 91 additions and 53 deletions

View File

@ -25,7 +25,7 @@ pub fn parse_mesh_surface<'a>(
arena: &'a MemArena,
tree: &'a DataTree,
) -> Result<TriangleMesh<'a>, 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,
))
}

View File

@ -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<Vec<Point>>,
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<usize> = (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.