Got basic material parsing and rendering working.
Currently only Lambert is supported.
This commit is contained in:
parent
f4d4152543
commit
516803e78a
|
@ -2,6 +2,7 @@ mod data_tree;
|
|||
mod psy_assembly;
|
||||
mod psy_light;
|
||||
mod psy_mesh_surface;
|
||||
mod psy_surface_shader;
|
||||
mod psy;
|
||||
pub mod basics;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use scene::{Assembly, AssemblyBuilder, Object};
|
|||
use super::DataTree;
|
||||
use super::psy_light::{parse_sphere_light, parse_rectangle_light};
|
||||
use super::psy_mesh_surface::parse_mesh_surface;
|
||||
use super::psy_surface_shader::parse_surface_shader;
|
||||
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
|
||||
};
|
||||
|
||||
// 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
|
||||
let mut xforms = Vec::new();
|
||||
for (_, contents, _) in child.iter_leaf_children_with_type("Transform") {
|
||||
|
@ -53,7 +70,7 @@ pub fn parse_assembly<'a>(
|
|||
|
||||
// Add instance
|
||||
if builder.name_exists(name) {
|
||||
builder.add_instance(name, Some(&xforms));
|
||||
builder.add_instance(name, surface_shader_name, Some(&xforms));
|
||||
} else {
|
||||
return Err(PsyParseError::InstancedMissingData(
|
||||
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" => {
|
||||
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
|
||||
}
|
||||
|
@ -143,12 +163,6 @@ pub fn parse_assembly<'a>(
|
|||
// else if (child.type == "Sphere") {
|
||||
// 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 {
|
||||
|
|
68
src/parse/psy_surface_shader.rs
Normal file
68
src/parse/psy_surface_shader.rs
Normal 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)
|
||||
}
|
|
@ -11,6 +11,7 @@ use lerp::lerp_slice;
|
|||
use light::LightSource;
|
||||
use math::{Matrix4x4, Vector};
|
||||
use surface::{Surface, SurfaceIntersection};
|
||||
use shading::SurfaceShader;
|
||||
use transform_stack::TransformStack;
|
||||
|
||||
|
||||
|
@ -21,6 +22,9 @@ pub struct Assembly<'a> {
|
|||
pub light_instances: &'a [Instance],
|
||||
pub xforms: &'a [Matrix4x4],
|
||||
|
||||
// Surface shader list
|
||||
pub surface_shaders: &'a [&'a SurfaceShader],
|
||||
|
||||
// Object list
|
||||
pub objects: &'a [Object<'a>],
|
||||
|
||||
|
@ -150,6 +154,10 @@ pub struct AssemblyBuilder<'a> {
|
|||
instances: Vec<Instance>,
|
||||
xforms: Vec<Matrix4x4>,
|
||||
|
||||
// Shader list
|
||||
surface_shaders: Vec<&'a SurfaceShader>,
|
||||
surface_shader_map: HashMap<String, usize>, // map Name -> Index
|
||||
|
||||
// Object list
|
||||
objects: Vec<Object<'a>>,
|
||||
object_map: HashMap<String, usize>, // map Name -> Index
|
||||
|
@ -166,6 +174,8 @@ impl<'a> AssemblyBuilder<'a> {
|
|||
arena: arena,
|
||||
instances: Vec::new(),
|
||||
xforms: Vec::new(),
|
||||
surface_shaders: Vec::new(),
|
||||
surface_shader_map: HashMap::new(),
|
||||
objects: Vec::new(),
|
||||
object_map: HashMap::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>) {
|
||||
// Make sure the name hasn't already been used.
|
||||
if self.name_exists(name) {
|
||||
|
@ -201,7 +225,12 @@ impl<'a> AssemblyBuilder<'a> {
|
|||
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
|
||||
if !self.name_exists(name) {
|
||||
panic!("Attempted to add instance with a name that doesn't exist.");
|
||||
|
@ -219,6 +248,12 @@ impl<'a> AssemblyBuilder<'a> {
|
|||
Instance {
|
||||
instance_type: InstanceType::Object,
|
||||
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(),
|
||||
transform_indices: xforms.map(
|
||||
|xf| (self.xforms.len(), self.xforms.len() + xf.len()),
|
||||
|
@ -228,6 +263,12 @@ impl<'a> AssemblyBuilder<'a> {
|
|||
Instance {
|
||||
instance_type: InstanceType::Assembly,
|
||||
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(),
|
||||
transform_indices: xforms.map(
|
||||
|xf| (self.xforms.len(), self.xforms.len() + xf.len()),
|
||||
|
@ -303,6 +344,7 @@ impl<'a> AssemblyBuilder<'a> {
|
|||
instances: self.arena.copy_slice(&self.instances),
|
||||
light_instances: self.arena.copy_slice(&light_instances),
|
||||
xforms: self.arena.copy_slice(&self.xforms),
|
||||
surface_shaders: self.arena.copy_slice(&self.surface_shaders),
|
||||
objects: self.arena.copy_slice(&self.objects),
|
||||
assemblies: self.arena.copy_slice(&self.assemblies),
|
||||
object_accel: object_accel,
|
||||
|
@ -370,6 +412,7 @@ pub enum Object<'a> {
|
|||
pub struct Instance {
|
||||
pub instance_type: InstanceType,
|
||||
pub data_index: usize,
|
||||
pub surface_shader_index: Option<usize>,
|
||||
pub id: usize,
|
||||
pub transform_indices: Option<(usize, usize)>,
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use self::surface_closure::{SurfaceClosureUnion, EmitClosure, LambertClosure, GT
|
|||
use surface::SurfaceIntersectionData;
|
||||
|
||||
/// Trait for surface shaders.
|
||||
pub trait SurfaceShader: Debug {
|
||||
pub trait SurfaceShader: Debug + Sync {
|
||||
/// Takes the result of a surface intersection and returns the surface
|
||||
/// closure to be evaluated at that intersection point.
|
||||
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
|
||||
/// them a great injustice, for they are each the size of a small
|
||||
/// building.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SimpleSurfaceShader {
|
||||
Emit { color: XYZ },
|
||||
Lambert { color: XYZ },
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::fmt::Debug;
|
|||
use boundable::Boundable;
|
||||
use math::{Point, Vector, Normal, Matrix4x4};
|
||||
use ray::{Ray, AccelRay};
|
||||
use shading::SurfaceShader;
|
||||
use shading::surface_closure::SurfaceClosureUnion;
|
||||
|
||||
|
||||
|
@ -17,6 +18,7 @@ pub trait Surface: Boundable + Debug + Sync {
|
|||
accel_rays: &mut [AccelRay],
|
||||
wrays: &[Ray],
|
||||
isects: &mut [SurfaceIntersection],
|
||||
shader: &SurfaceShader,
|
||||
space: &[Matrix4x4],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ use mem_arena::MemArena;
|
|||
use accel::BVH4;
|
||||
use bbox::BBox;
|
||||
use boundable::Boundable;
|
||||
use color::XYZ;
|
||||
use fp_utils::fp_gamma;
|
||||
use lerp::lerp_slice;
|
||||
use math::{Point, Normal, Matrix4x4, dot, cross};
|
||||
use ray::{Ray, AccelRay};
|
||||
use shading::{SurfaceShader, SimpleSurfaceShader};
|
||||
use shading::SurfaceShader;
|
||||
|
||||
use super::{Surface, SurfaceIntersection, SurfaceIntersectionData};
|
||||
use super::triangle;
|
||||
|
@ -123,6 +122,7 @@ impl<'a> Surface for TriangleMesh<'a> {
|
|||
accel_rays: &mut [AccelRay],
|
||||
wrays: &[Ray],
|
||||
isects: &mut [SurfaceIntersection],
|
||||
shader: &SurfaceShader,
|
||||
space: &[Matrix4x4],
|
||||
) {
|
||||
// Precalculate transform for non-motion blur cases
|
||||
|
@ -249,16 +249,7 @@ impl<'a> Surface for TriangleMesh<'a> {
|
|||
// Fill in intersection data
|
||||
isects[r.id as usize] = SurfaceIntersection::Hit {
|
||||
intersection_data: intersection_data,
|
||||
// TODO: get surface shader from user-defined shader.
|
||||
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),
|
||||
closure: shader.shade(&intersection_data, wr.wavelength),
|
||||
};
|
||||
r.max_t = t;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use ray::{Ray, AccelRay};
|
|||
use scene::{Assembly, Object, InstanceType};
|
||||
use surface::SurfaceIntersection;
|
||||
use transform_stack::TransformStack;
|
||||
use shading::{SurfaceShader, SimpleSurfaceShader};
|
||||
use color::XYZ;
|
||||
|
||||
|
||||
pub struct Tracer<'a> {
|
||||
|
@ -128,6 +130,9 @@ impl<'a> TracerInner<'a> {
|
|||
InstanceType::Object => {
|
||||
self.trace_object(
|
||||
&assembly.objects[inst.data_index],
|
||||
inst.surface_shader_index.map(
|
||||
|i| assembly.surface_shaders[i],
|
||||
),
|
||||
wrays,
|
||||
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 {
|
||||
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(_) => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user