Got basic material parsing and rendering working.

Currently only Lambert is supported.
This commit is contained in:
Nathan Vegdahl 2017-08-03 19:31:58 -07:00
parent f4d4152543
commit 516803e78a
8 changed files with 175 additions and 35 deletions

View File

@ -2,6 +2,7 @@ mod data_tree;
mod psy_assembly; mod psy_assembly;
mod psy_light; mod psy_light;
mod psy_mesh_surface; mod psy_mesh_surface;
mod psy_surface_shader;
mod psy; mod psy;
pub mod basics; pub mod basics;

View File

@ -9,6 +9,7 @@ use scene::{Assembly, AssemblyBuilder, Object};
use super::DataTree; use super::DataTree;
use super::psy_light::{parse_sphere_light, parse_rectangle_light}; use super::psy_light::{parse_sphere_light, parse_rectangle_light};
use super::psy_mesh_surface::parse_mesh_surface; use super::psy_mesh_surface::parse_mesh_surface;
use super::psy_surface_shader::parse_surface_shader;
use super::psy::{parse_matrix, PsyParseError}; use super::psy::{parse_matrix, PsyParseError};
@ -45,6 +46,22 @@ pub fn parse_assembly<'a>(
child.iter_leaf_children_with_type("Data").nth(0).unwrap().1 child.iter_leaf_children_with_type("Data").nth(0).unwrap().1
}; };
// Get surface shader binding, if any.
let surface_shader_name = if child
.iter_leaf_children_with_type("SurfaceShaderBind")
.count() > 0
{
Some(
child
.iter_leaf_children_with_type("SurfaceShaderBind")
.nth(0)
.unwrap()
.1,
)
} else {
None
};
// Get xforms // Get xforms
let mut xforms = Vec::new(); let mut xforms = Vec::new();
for (_, contents, _) in child.iter_leaf_children_with_type("Transform") { for (_, contents, _) in child.iter_leaf_children_with_type("Transform") {
@ -53,7 +70,7 @@ pub fn parse_assembly<'a>(
// Add instance // Add instance
if builder.name_exists(name) { if builder.name_exists(name) {
builder.add_instance(name, Some(&xforms)); builder.add_instance(name, surface_shader_name, Some(&xforms));
} else { } else {
return Err(PsyParseError::InstancedMissingData( return Err(PsyParseError::InstancedMissingData(
child.iter_leaf_children_with_type("Data").nth(0).unwrap().2, child.iter_leaf_children_with_type("Data").nth(0).unwrap().2,
@ -66,6 +83,20 @@ pub fn parse_assembly<'a>(
} }
} }
// SurfaceShader
"SurfaceShader" => {
if let DataTree::Internal { ident: Some(ident), .. } = *child {
builder.add_surface_shader(ident, parse_surface_shader(arena, child)?);
} else {
// TODO: error condition of some kind, because no ident
panic!(
"SurfaceShader encountered that was a leaf, but SurfaceShaders cannot \
be a leaf: {}",
child.byte_offset()
);
}
}
// MeshSurface // MeshSurface
"MeshSurface" => { "MeshSurface" => {
if let DataTree::Internal { ident: Some(ident), .. } = *child { if let DataTree::Internal { ident: Some(ident), .. } = *child {
@ -109,17 +140,6 @@ pub fn parse_assembly<'a>(
} }
} }
// Surface shader
"SurfaceShader" => {
if let DataTree::Internal { ident: Some(_), .. } = *child {
// TODO
//unimplemented!()
} else {
// No ident
return Err(PsyParseError::UnknownError(child.byte_offset()));
}
}
_ => { _ => {
// TODO: some kind of error, because not a known type name // TODO: some kind of error, because not a known type name
} }
@ -143,12 +163,6 @@ pub fn parse_assembly<'a>(
// else if (child.type == "Sphere") { // else if (child.type == "Sphere") {
// assembly->add_object(child.name, parse_sphere(child)); // assembly->add_object(child.name, parse_sphere(child));
// } // }
//
// // Surface shader
// else if (child.type == "SurfaceShader") {
// assembly->add_surface_shader(child.name, parse_surface_shader(child));
// }
//
} }
} }
} else { } else {

View File

@ -0,0 +1,68 @@
#![allow(dead_code)]
use std::result::Result;
use nom::IResult;
use mem_arena::MemArena;
use color::{XYZ, rec709_e_to_xyz};
use shading::{SurfaceShader, SimpleSurfaceShader};
use super::basics::ws_f32;
use super::DataTree;
use super::psy::PsyParseError;
// pub struct TriangleMesh {
// time_samples: usize,
// geo: Vec<(Point, Point, Point)>,
// indices: Vec<usize>,
// accel: BVH,
// }
pub fn parse_surface_shader<'a>(
arena: &'a MemArena,
tree: &'a DataTree,
) -> Result<&'a SurfaceShader, PsyParseError> {
let type_name = if let Some((_, text, _)) = tree.iter_leaf_children_with_type("Type").nth(0) {
text.trim()
} else {
return Err(PsyParseError::MissingNode(
tree.byte_offset(),
"Expected a Type field in SurfaceShader.",
));
};
let shader = match type_name {
"Emit" => unimplemented!(),
"Lambert" => {
let color = if let Some((_, contents, byte_offset)) =
tree.iter_leaf_children_with_type("Color").nth(0)
{
if let IResult::Done(_, color) =
closure!(tuple!(ws_f32, ws_f32, ws_f32))(contents.as_bytes())
{
// TODO: handle color space conversions properly.
// Probably will need a special color type with its
// own parser...?
XYZ::from_tuple(rec709_e_to_xyz(color))
} else {
// Found color, but its contents is not in the right format
return Err(PsyParseError::UnknownError(byte_offset));
}
} else {
return Err(PsyParseError::MissingNode(
tree.byte_offset(),
"Expected a Color field in Lambert SurfaceShader.",
));
};
arena.alloc(SimpleSurfaceShader::Lambert { color: color })
}
"GTR" => unimplemented!(),
_ => unimplemented!(),
};
Ok(shader)
}

View File

@ -11,6 +11,7 @@ use lerp::lerp_slice;
use light::LightSource; use light::LightSource;
use math::{Matrix4x4, Vector}; use math::{Matrix4x4, Vector};
use surface::{Surface, SurfaceIntersection}; use surface::{Surface, SurfaceIntersection};
use shading::SurfaceShader;
use transform_stack::TransformStack; use transform_stack::TransformStack;
@ -21,6 +22,9 @@ pub struct Assembly<'a> {
pub light_instances: &'a [Instance], pub light_instances: &'a [Instance],
pub xforms: &'a [Matrix4x4], pub xforms: &'a [Matrix4x4],
// Surface shader list
pub surface_shaders: &'a [&'a SurfaceShader],
// Object list // Object list
pub objects: &'a [Object<'a>], pub objects: &'a [Object<'a>],
@ -150,6 +154,10 @@ pub struct AssemblyBuilder<'a> {
instances: Vec<Instance>, instances: Vec<Instance>,
xforms: Vec<Matrix4x4>, xforms: Vec<Matrix4x4>,
// Shader list
surface_shaders: Vec<&'a SurfaceShader>,
surface_shader_map: HashMap<String, usize>, // map Name -> Index
// Object list // Object list
objects: Vec<Object<'a>>, objects: Vec<Object<'a>>,
object_map: HashMap<String, usize>, // map Name -> Index object_map: HashMap<String, usize>, // map Name -> Index
@ -166,6 +174,8 @@ impl<'a> AssemblyBuilder<'a> {
arena: arena, arena: arena,
instances: Vec::new(), instances: Vec::new(),
xforms: Vec::new(), xforms: Vec::new(),
surface_shaders: Vec::new(),
surface_shader_map: HashMap::new(),
objects: Vec::new(), objects: Vec::new(),
object_map: HashMap::new(), object_map: HashMap::new(),
assemblies: Vec::new(), assemblies: Vec::new(),
@ -173,6 +183,20 @@ impl<'a> AssemblyBuilder<'a> {
} }
} }
pub fn add_surface_shader(&mut self, name: &str, shader: &'a SurfaceShader) {
// Make sure the name hasn't already been used.
if self.surface_shader_map.contains_key(name) {
panic!("Attempted to add surface shader to assembly with a name that already exists.");
}
// Add shader
self.surface_shader_map.insert(
name.to_string(),
self.surface_shaders.len(),
);
self.surface_shaders.push(shader);
}
pub fn add_object(&mut self, name: &str, obj: Object<'a>) { pub fn add_object(&mut self, name: &str, obj: Object<'a>) {
// Make sure the name hasn't already been used. // Make sure the name hasn't already been used.
if self.name_exists(name) { if self.name_exists(name) {
@ -201,7 +225,12 @@ impl<'a> AssemblyBuilder<'a> {
self.assemblies.push(asmb); self.assemblies.push(asmb);
} }
pub fn add_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) { pub fn add_instance(
&mut self,
name: &str,
surface_shader_name: Option<&str>,
xforms: Option<&[Matrix4x4]>,
) {
// Make sure name exists // Make sure name exists
if !self.name_exists(name) { if !self.name_exists(name) {
panic!("Attempted to add instance with a name that doesn't exist."); panic!("Attempted to add instance with a name that doesn't exist.");
@ -219,6 +248,12 @@ impl<'a> AssemblyBuilder<'a> {
Instance { Instance {
instance_type: InstanceType::Object, instance_type: InstanceType::Object,
data_index: self.object_map[name], data_index: self.object_map[name],
surface_shader_index: surface_shader_name.map(|name| {
*self.surface_shader_map.get(name).expect(&format!(
"Unknown surface shader '{}'.",
name
))
}),
id: self.instances.len(), id: self.instances.len(),
transform_indices: xforms.map( transform_indices: xforms.map(
|xf| (self.xforms.len(), self.xforms.len() + xf.len()), |xf| (self.xforms.len(), self.xforms.len() + xf.len()),
@ -228,6 +263,12 @@ impl<'a> AssemblyBuilder<'a> {
Instance { Instance {
instance_type: InstanceType::Assembly, instance_type: InstanceType::Assembly,
data_index: self.assembly_map[name], data_index: self.assembly_map[name],
surface_shader_index: surface_shader_name.map(|name| {
*self.surface_shader_map.get(name).expect(&format!(
"Unknown surface shader '{}'.",
name
))
}),
id: self.instances.len(), id: self.instances.len(),
transform_indices: xforms.map( transform_indices: xforms.map(
|xf| (self.xforms.len(), self.xforms.len() + xf.len()), |xf| (self.xforms.len(), self.xforms.len() + xf.len()),
@ -303,6 +344,7 @@ impl<'a> AssemblyBuilder<'a> {
instances: self.arena.copy_slice(&self.instances), instances: self.arena.copy_slice(&self.instances),
light_instances: self.arena.copy_slice(&light_instances), light_instances: self.arena.copy_slice(&light_instances),
xforms: self.arena.copy_slice(&self.xforms), xforms: self.arena.copy_slice(&self.xforms),
surface_shaders: self.arena.copy_slice(&self.surface_shaders),
objects: self.arena.copy_slice(&self.objects), objects: self.arena.copy_slice(&self.objects),
assemblies: self.arena.copy_slice(&self.assemblies), assemblies: self.arena.copy_slice(&self.assemblies),
object_accel: object_accel, object_accel: object_accel,
@ -370,6 +412,7 @@ pub enum Object<'a> {
pub struct Instance { pub struct Instance {
pub instance_type: InstanceType, pub instance_type: InstanceType,
pub data_index: usize, pub data_index: usize,
pub surface_shader_index: Option<usize>,
pub id: usize, pub id: usize,
pub transform_indices: Option<(usize, usize)>, pub transform_indices: Option<(usize, usize)>,
} }

View File

@ -7,7 +7,7 @@ use self::surface_closure::{SurfaceClosureUnion, EmitClosure, LambertClosure, GT
use surface::SurfaceIntersectionData; use surface::SurfaceIntersectionData;
/// Trait for surface shaders. /// Trait for surface shaders.
pub trait SurfaceShader: Debug { pub trait SurfaceShader: Debug + Sync {
/// Takes the result of a surface intersection and returns the surface /// Takes the result of a surface intersection and returns the surface
/// closure to be evaluated at that intersection point. /// closure to be evaluated at that intersection point.
fn shade(&self, data: &SurfaceIntersectionData, wavelength: f32) -> SurfaceClosureUnion; fn shade(&self, data: &SurfaceIntersectionData, wavelength: f32) -> SurfaceClosureUnion;
@ -24,7 +24,7 @@ pub trait SurfaceShader: Debug {
/// are no ordinary donuts. To call them large is actually doing /// are no ordinary donuts. To call them large is actually doing
/// them a great injustice, for they are each the size of a small /// them a great injustice, for they are each the size of a small
/// building. /// building.
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub enum SimpleSurfaceShader { pub enum SimpleSurfaceShader {
Emit { color: XYZ }, Emit { color: XYZ },
Lambert { color: XYZ }, Lambert { color: XYZ },

View File

@ -8,6 +8,7 @@ use std::fmt::Debug;
use boundable::Boundable; use boundable::Boundable;
use math::{Point, Vector, Normal, Matrix4x4}; use math::{Point, Vector, Normal, Matrix4x4};
use ray::{Ray, AccelRay}; use ray::{Ray, AccelRay};
use shading::SurfaceShader;
use shading::surface_closure::SurfaceClosureUnion; use shading::surface_closure::SurfaceClosureUnion;
@ -17,6 +18,7 @@ pub trait Surface: Boundable + Debug + Sync {
accel_rays: &mut [AccelRay], accel_rays: &mut [AccelRay],
wrays: &[Ray], wrays: &[Ray],
isects: &mut [SurfaceIntersection], isects: &mut [SurfaceIntersection],
shader: &SurfaceShader,
space: &[Matrix4x4], space: &[Matrix4x4],
); );
} }

View File

@ -5,12 +5,11 @@ use mem_arena::MemArena;
use accel::BVH4; use accel::BVH4;
use bbox::BBox; use bbox::BBox;
use boundable::Boundable; use boundable::Boundable;
use color::XYZ;
use fp_utils::fp_gamma; use fp_utils::fp_gamma;
use lerp::lerp_slice; use lerp::lerp_slice;
use math::{Point, Normal, Matrix4x4, dot, cross}; use math::{Point, Normal, Matrix4x4, dot, cross};
use ray::{Ray, AccelRay}; use ray::{Ray, AccelRay};
use shading::{SurfaceShader, SimpleSurfaceShader}; use shading::SurfaceShader;
use super::{Surface, SurfaceIntersection, SurfaceIntersectionData}; use super::{Surface, SurfaceIntersection, SurfaceIntersectionData};
use super::triangle; use super::triangle;
@ -123,6 +122,7 @@ impl<'a> Surface for TriangleMesh<'a> {
accel_rays: &mut [AccelRay], accel_rays: &mut [AccelRay],
wrays: &[Ray], wrays: &[Ray],
isects: &mut [SurfaceIntersection], isects: &mut [SurfaceIntersection],
shader: &SurfaceShader,
space: &[Matrix4x4], space: &[Matrix4x4],
) { ) {
// Precalculate transform for non-motion blur cases // Precalculate transform for non-motion blur cases
@ -249,16 +249,7 @@ impl<'a> Surface for TriangleMesh<'a> {
// Fill in intersection data // Fill in intersection data
isects[r.id as usize] = SurfaceIntersection::Hit { isects[r.id as usize] = SurfaceIntersection::Hit {
intersection_data: intersection_data, intersection_data: intersection_data,
// TODO: get surface shader from user-defined shader. closure: shader.shade(&intersection_data, wr.wavelength),
closure: SimpleSurfaceShader::Lambert {
color: XYZ::new(0.8, 0.8, 0.8),
}.shade(&intersection_data, wr.wavelength),
// closure: SimpleSurfaceShader::GTR {
// color: XYZ::new(0.8, 0.8, 0.8),
// roughness: 0.1,
// tail_shape: 2.0,
// fresnel: 1.0,
// }.shade(&intersection_data, wr.wavelength),
}; };
r.max_t = t; r.max_t = t;
} }

View File

@ -6,6 +6,8 @@ use ray::{Ray, AccelRay};
use scene::{Assembly, Object, InstanceType}; use scene::{Assembly, Object, InstanceType};
use surface::SurfaceIntersection; use surface::SurfaceIntersection;
use transform_stack::TransformStack; use transform_stack::TransformStack;
use shading::{SurfaceShader, SimpleSurfaceShader};
use color::XYZ;
pub struct Tracer<'a> { pub struct Tracer<'a> {
@ -128,6 +130,9 @@ impl<'a> TracerInner<'a> {
InstanceType::Object => { InstanceType::Object => {
self.trace_object( self.trace_object(
&assembly.objects[inst.data_index], &assembly.objects[inst.data_index],
inst.surface_shader_index.map(
|i| assembly.surface_shaders[i],
),
wrays, wrays,
ray_set, ray_set,
); );
@ -171,10 +176,26 @@ impl<'a> TracerInner<'a> {
); );
} }
fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [AccelRay]) { fn trace_object<'b>(
&'b mut self,
obj: &Object,
surface_shader: Option<&SurfaceShader>,
wrays: &[Ray],
rays: &mut [AccelRay],
) {
match *obj { match *obj {
Object::Surface(surface) => { Object::Surface(surface) => {
surface.intersect_rays(rays, wrays, &mut self.isects, self.xform_stack.top()); let unassigned_shader =
SimpleSurfaceShader::Lambert { color: XYZ::new(1.0, 0.0, 1.0) };
let shader = surface_shader.unwrap_or(&unassigned_shader);
surface.intersect_rays(
rays,
wrays,
&mut self.isects,
shader,
self.xform_stack.top(),
);
} }
Object::Light(_) => { Object::Light(_) => {