Implemented smooth-shaded triangle meshes.
There are still some things to do to avoid light leakage and other weird shading in some situations, but the basics are working!
This commit is contained in:
parent
e77d5b7576
commit
05578a1240
|
@ -166,11 +166,15 @@ class Mesh:
|
||||||
w.write("SubdivisionSurface $%s {\n" % self.name)
|
w.write("SubdivisionSurface $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
|
|
||||||
# Write vertices
|
# Write vertices and (if it's smooth shaded) normals
|
||||||
for ti in range(len(self.time_meshes)):
|
for ti in range(len(self.time_meshes)):
|
||||||
w.write("Vertices [")
|
w.write("Vertices [")
|
||||||
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.co]), False)
|
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.co]), False)
|
||||||
w.write("]\n", False)
|
w.write("]\n", False)
|
||||||
|
if self.time_meshes[0].polygons[0].use_smooth and self.ob.data.psychopath.is_subdivision_surface == False:
|
||||||
|
w.write("Normals [")
|
||||||
|
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.normal]), False)
|
||||||
|
w.write("]\n", False)
|
||||||
|
|
||||||
# Write face vertex counts
|
# Write face vertex counts
|
||||||
w.write("FaceVertCounts [")
|
w.write("FaceVertCounts [")
|
||||||
|
|
|
@ -6,7 +6,7 @@ use nom::IResult;
|
||||||
|
|
||||||
use mem_arena::MemArena;
|
use mem_arena::MemArena;
|
||||||
|
|
||||||
use math::Point;
|
use math::{Point, Normal};
|
||||||
use surface::triangle_mesh::TriangleMesh;
|
use surface::triangle_mesh::TriangleMesh;
|
||||||
|
|
||||||
use super::basics::{ws_usize, ws_f32};
|
use super::basics::{ws_usize, ws_f32};
|
||||||
|
@ -26,6 +26,7 @@ pub fn parse_mesh_surface<'a>(
|
||||||
tree: &'a DataTree,
|
tree: &'a DataTree,
|
||||||
) -> Result<TriangleMesh<'a>, PsyParseError> {
|
) -> Result<TriangleMesh<'a>, PsyParseError> {
|
||||||
let mut verts = Vec::new(); // Vec of vecs, one for each time sample
|
let mut verts = Vec::new(); // Vec of vecs, one for each time sample
|
||||||
|
let mut normals = Vec::new(); // Vec of vecs, on for each time sample
|
||||||
let mut face_vert_counts = Vec::new();
|
let mut face_vert_counts = Vec::new();
|
||||||
let mut face_vert_indices = Vec::new();
|
let mut face_vert_indices = Vec::new();
|
||||||
|
|
||||||
|
@ -54,6 +55,30 @@ pub fn parse_mesh_surface<'a>(
|
||||||
assert_eq!(vert_count, vs.len());
|
assert_eq!(vert_count, vs.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get normals, if they exist
|
||||||
|
for (_, text, _) in tree.iter_leaf_children_with_type("Normals") {
|
||||||
|
let mut raw_text = text.trim().as_bytes();
|
||||||
|
|
||||||
|
// Collect verts for this time sample
|
||||||
|
let mut tnormals = Vec::new();
|
||||||
|
while let IResult::Done(remaining, nor) =
|
||||||
|
closure!(tuple!(ws_f32, ws_f32, ws_f32))(raw_text)
|
||||||
|
{
|
||||||
|
raw_text = remaining;
|
||||||
|
|
||||||
|
tnormals.push(Normal::new(nor.0, nor.1, nor.2).normalized());
|
||||||
|
}
|
||||||
|
normals.push(tnormals);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure normal's time samples and vert count match the vertices
|
||||||
|
if !normals.is_empty() {
|
||||||
|
assert_eq!(normals.len(), verts.len());
|
||||||
|
for ns in &normals {
|
||||||
|
assert_eq!(vert_count, ns.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get face vert counts
|
// Get face vert counts
|
||||||
if let Some((_, text, _)) = tree.iter_leaf_children_with_type("FaceVertCounts").nth(0) {
|
if let Some((_, text, _)) = tree.iter_leaf_children_with_type("FaceVertCounts").nth(0) {
|
||||||
let mut raw_text = text.trim().as_bytes();
|
let mut raw_text = text.trim().as_bytes();
|
||||||
|
@ -101,6 +126,11 @@ pub fn parse_mesh_surface<'a>(
|
||||||
Ok(TriangleMesh::from_verts_and_indices(
|
Ok(TriangleMesh::from_verts_and_indices(
|
||||||
arena,
|
arena,
|
||||||
verts,
|
verts,
|
||||||
|
if normals.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(normals)
|
||||||
|
},
|
||||||
tri_vert_indices,
|
tri_vert_indices,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use boundable::Boundable;
|
||||||
use color::XYZ;
|
use color::XYZ;
|
||||||
use fp_utils::fp_gamma;
|
use fp_utils::fp_gamma;
|
||||||
use lerp::lerp_slice;
|
use lerp::lerp_slice;
|
||||||
use math::{Point, Matrix4x4, cross};
|
use math::{Point, Normal, Matrix4x4, dot, cross};
|
||||||
use ray::{Ray, AccelRay};
|
use ray::{Ray, AccelRay};
|
||||||
use shading::surface_closure::{SurfaceClosureUnion, GTRClosure, LambertClosure};
|
use shading::surface_closure::{SurfaceClosureUnion, GTRClosure, LambertClosure};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ use super::triangle;
|
||||||
pub struct TriangleMesh<'a> {
|
pub struct TriangleMesh<'a> {
|
||||||
time_sample_count: usize,
|
time_sample_count: usize,
|
||||||
vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously
|
vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously
|
||||||
|
normals: Option<&'a [Normal]>, // Vertex normals, organized the same as `vertices`
|
||||||
indices: &'a [(u32, u32, u32, u32)], // (v0_idx, v1_idx, v2_idx, original_tri_idx)
|
indices: &'a [(u32, u32, u32, u32)], // (v0_idx, v1_idx, v2_idx, original_tri_idx)
|
||||||
accel: BVH4<'a>,
|
accel: BVH4<'a>,
|
||||||
}
|
}
|
||||||
|
@ -28,6 +29,7 @@ impl<'a> TriangleMesh<'a> {
|
||||||
pub fn from_verts_and_indices<'b>(
|
pub fn from_verts_and_indices<'b>(
|
||||||
arena: &'b MemArena,
|
arena: &'b MemArena,
|
||||||
verts: Vec<Vec<Point>>,
|
verts: Vec<Vec<Point>>,
|
||||||
|
vert_normals: Option<Vec<Vec<Normal>>>,
|
||||||
tri_indices: Vec<(usize, usize, usize)>,
|
tri_indices: Vec<(usize, usize, usize)>,
|
||||||
) -> TriangleMesh<'b> {
|
) -> TriangleMesh<'b> {
|
||||||
let vert_count = verts[0].len();
|
let vert_count = verts[0].len();
|
||||||
|
@ -48,6 +50,25 @@ impl<'a> TriangleMesh<'a> {
|
||||||
vertices
|
vertices
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Copy vertex normals, if any, organizing them the same as vertices
|
||||||
|
// above.
|
||||||
|
let normals = match vert_normals {
|
||||||
|
Some(ref vnors) => {
|
||||||
|
let mut normals =
|
||||||
|
unsafe { arena.alloc_array_uninitialized(vert_count * time_sample_count) };
|
||||||
|
|
||||||
|
for vi in 0..vert_count {
|
||||||
|
for ti in 0..time_sample_count {
|
||||||
|
normals[(vi * time_sample_count) + ti] = vnors[ti][vi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&normals[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
// Copy triangle vertex indices over, appending the triangle index itself to the tuple
|
// Copy triangle vertex indices over, appending the triangle index itself to the tuple
|
||||||
let mut indices = {
|
let mut indices = {
|
||||||
let mut indices = unsafe { arena.alloc_array_uninitialized(tri_indices.len()) };
|
let mut indices = unsafe { arena.alloc_array_uninitialized(tri_indices.len()) };
|
||||||
|
@ -82,6 +103,7 @@ impl<'a> TriangleMesh<'a> {
|
||||||
TriangleMesh {
|
TriangleMesh {
|
||||||
time_sample_count: time_sample_count,
|
time_sample_count: time_sample_count,
|
||||||
vertices: vertices,
|
vertices: vertices,
|
||||||
|
normals: normals,
|
||||||
indices: indices,
|
indices: indices,
|
||||||
accel: accel,
|
accel: accel,
|
||||||
}
|
}
|
||||||
|
@ -110,106 +132,138 @@ impl<'a> Surface for TriangleMesh<'a> {
|
||||||
Matrix4x4::new()
|
Matrix4x4::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.accel
|
self.accel.traverse(
|
||||||
.traverse(
|
&mut accel_rays[..],
|
||||||
&mut accel_rays[..], self.indices, |tri_indices, rs| {
|
self.indices,
|
||||||
for r in rs {
|
|tri_indices, rs| {
|
||||||
let wr = &wrays[r.id as usize];
|
for r in rs {
|
||||||
|
let wr = &wrays[r.id as usize];
|
||||||
|
|
||||||
// Get triangle
|
// Get triangle
|
||||||
let tri = {
|
let tri = {
|
||||||
let p0_slice = &self.vertices[
|
let p0_slice = &self.vertices[(tri_indices.0 as usize *
|
||||||
(tri_indices.0 as usize * self.time_sample_count)..
|
self.time_sample_count)..
|
||||||
((tri_indices.0 as usize + 1) * self.time_sample_count)
|
((tri_indices.0 as usize + 1) *
|
||||||
];
|
self.time_sample_count)];
|
||||||
let p1_slice = &self.vertices[
|
let p1_slice = &self.vertices[(tri_indices.1 as usize *
|
||||||
(tri_indices.1 as usize * self.time_sample_count)..
|
self.time_sample_count)..
|
||||||
((tri_indices.1 as usize + 1) * self.time_sample_count)
|
((tri_indices.1 as usize + 1) *
|
||||||
];
|
self.time_sample_count)];
|
||||||
let p2_slice = &self.vertices[
|
let p2_slice = &self.vertices[(tri_indices.2 as usize *
|
||||||
(tri_indices.2 as usize * self.time_sample_count)..
|
self.time_sample_count)..
|
||||||
((tri_indices.2 as usize + 1) * self.time_sample_count)
|
((tri_indices.2 as usize + 1) *
|
||||||
];
|
self.time_sample_count)];
|
||||||
|
|
||||||
let p0 = lerp_slice(p0_slice, wr.time);
|
let p0 = lerp_slice(p0_slice, wr.time);
|
||||||
let p1 = lerp_slice(p1_slice, wr.time);
|
let p1 = lerp_slice(p1_slice, wr.time);
|
||||||
let p2 = lerp_slice(p2_slice, wr.time);
|
let p2 = lerp_slice(p2_slice, wr.time);
|
||||||
|
|
||||||
(p0, p1, p2)
|
(p0, p1, p2)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transform triangle as necessary, and get transform
|
// Transform triangle as necessary, and get transform
|
||||||
// space.
|
// space.
|
||||||
let (mat_space, tri) = if !space.is_empty() {
|
let (mat_space, tri) = if !space.is_empty() {
|
||||||
if space.len() > 1 {
|
if space.len() > 1 {
|
||||||
// Per-ray transform, for motion blur
|
// Per-ray transform, for motion blur
|
||||||
let mat_space = lerp_slice(space, wr.time).inverse();
|
let mat_space = lerp_slice(space, wr.time).inverse();
|
||||||
(mat_space,
|
(mat_space, (
|
||||||
(tri.0 * mat_space,
|
tri.0 * mat_space,
|
||||||
tri.1 * mat_space,
|
tri.1 * mat_space,
|
||||||
tri.2 * mat_space)
|
tri.2 * mat_space,
|
||||||
)
|
))
|
||||||
} else {
|
|
||||||
// Same transform for all rays
|
|
||||||
(static_mat_space,
|
|
||||||
(tri.0 * static_mat_space,
|
|
||||||
tri.1 * static_mat_space,
|
|
||||||
tri.2 * static_mat_space)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// No transforms
|
// Same transform for all rays
|
||||||
(Matrix4x4::new(), tri)
|
(static_mat_space, (
|
||||||
};
|
tri.0 * static_mat_space,
|
||||||
|
tri.1 * static_mat_space,
|
||||||
|
tri.2 * static_mat_space,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No transforms
|
||||||
|
(Matrix4x4::new(), tri)
|
||||||
|
};
|
||||||
|
|
||||||
// Test ray against triangle
|
// Test ray against triangle
|
||||||
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(wr, tri) {
|
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(wr, tri) {
|
||||||
if t < r.max_t {
|
if t < r.max_t {
|
||||||
if r.is_occlusion() {
|
if r.is_occlusion() {
|
||||||
isects[r.id as usize] = SurfaceIntersection::Occlude;
|
isects[r.id as usize] = SurfaceIntersection::Occlude;
|
||||||
r.mark_done();
|
r.mark_done();
|
||||||
|
} else {
|
||||||
|
// Calculate intersection point and error magnitudes
|
||||||
|
let pos = ((tri.0.into_vector() * b0) + (tri.1.into_vector() * b1) +
|
||||||
|
(tri.2.into_vector() * b2))
|
||||||
|
.into_point();
|
||||||
|
|
||||||
|
let pos_err = (((tri.0.into_vector().abs() * b0) +
|
||||||
|
(tri.1.into_vector().abs() * b1) +
|
||||||
|
(tri.2.into_vector().abs() * b2)) *
|
||||||
|
fp_gamma(7)).co
|
||||||
|
.h_max();
|
||||||
|
|
||||||
|
// Calculate geometric surface normal
|
||||||
|
let geo_normal = cross(tri.0 - tri.1, tri.0 - tri.2).into_normal();
|
||||||
|
|
||||||
|
// Calculate interpolated surface normal, if any
|
||||||
|
let shading_normal = if let Some(normals) = self.normals {
|
||||||
|
let n0_slice = &normals[(tri_indices.0 as usize *
|
||||||
|
self.time_sample_count)..
|
||||||
|
((tri_indices.0 as usize + 1) *
|
||||||
|
self.time_sample_count)];
|
||||||
|
let n1_slice = &normals[(tri_indices.1 as usize *
|
||||||
|
self.time_sample_count)..
|
||||||
|
((tri_indices.1 as usize + 1) *
|
||||||
|
self.time_sample_count)];
|
||||||
|
let n2_slice = &normals[(tri_indices.2 as usize *
|
||||||
|
self.time_sample_count)..
|
||||||
|
((tri_indices.2 as usize + 1) *
|
||||||
|
self.time_sample_count)];
|
||||||
|
|
||||||
|
let n0 = lerp_slice(n0_slice, wr.time).normalized();
|
||||||
|
let n1 = lerp_slice(n1_slice, wr.time).normalized();
|
||||||
|
let n2 = lerp_slice(n2_slice, wr.time).normalized();
|
||||||
|
|
||||||
|
let s_nor = (n0 * b0) + (n1 * b1) + (n2 * b2);
|
||||||
|
if dot(s_nor, geo_normal) >= 0.0 {
|
||||||
|
s_nor
|
||||||
|
} else {
|
||||||
|
-s_nor
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Calculate intersection point and error magnitudes
|
geo_normal
|
||||||
let pos = ((tri.0.into_vector() * b0)
|
};
|
||||||
+ (tri.1.into_vector() * b1)
|
|
||||||
+ (tri.2.into_vector() * b2)).into_point();
|
|
||||||
|
|
||||||
let pos_err = (((tri.0.into_vector().abs() * b0)
|
// Fill in intersection data
|
||||||
+ (tri.1.into_vector().abs() * b1)
|
isects[r.id as usize] = SurfaceIntersection::Hit {
|
||||||
+ (tri.2.into_vector().abs() * b2))
|
intersection_data: SurfaceIntersectionData {
|
||||||
* fp_gamma(7)).co.h_max();
|
incoming: wr.dir,
|
||||||
|
t: t,
|
||||||
// Fill in intersection data
|
pos: pos,
|
||||||
isects[r.id as usize] = SurfaceIntersection::Hit {
|
pos_err: pos_err,
|
||||||
intersection_data: SurfaceIntersectionData {
|
nor: shading_normal,
|
||||||
incoming: wr.dir,
|
nor_g: geo_normal,
|
||||||
t: t,
|
uv: (0.0, 0.0), // TODO
|
||||||
pos: pos,
|
local_space: mat_space,
|
||||||
pos_err: pos_err,
|
},
|
||||||
nor: cross(tri.0 - tri.1, tri.0 - tri.2)
|
// TODO: get surface closure from surface shader.
|
||||||
.into_normal(), // TODO
|
closure: SurfaceClosureUnion::LambertClosure(
|
||||||
nor_g: cross(tri.0 - tri.1, tri.0 - tri.2)
|
LambertClosure::new(XYZ::new(0.8, 0.8, 0.8)),
|
||||||
.into_normal(),
|
),
|
||||||
uv: (0.0, 0.0), // TODO
|
|
||||||
local_space: mat_space,
|
|
||||||
},
|
|
||||||
// TODO: get surface closure from surface shader.
|
|
||||||
closure: SurfaceClosureUnion::LambertClosure(
|
|
||||||
LambertClosure::new(XYZ::new(0.8, 0.8, 0.8))
|
|
||||||
),
|
|
||||||
// closure:
|
// closure:
|
||||||
// SurfaceClosureUnion::GTRClosure(
|
// SurfaceClosureUnion::GTRClosure(
|
||||||
// GTRClosure::new(XYZ::new(0.8, 0.8, 0.8),
|
// GTRClosure::new(XYZ::new(0.8, 0.8, 0.8),
|
||||||
// 0.1,
|
// 0.1,
|
||||||
// 2.0,
|
// 2.0,
|
||||||
// 1.0)),
|
// 1.0)),
|
||||||
};
|
};
|
||||||
r.max_t = t;
|
r.max_t = t;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user