Laying some groundwork for a simple shading system.

This commit is contained in:
Nathan Vegdahl 2017-03-14 00:27:25 -07:00
parent 114f11c583
commit 4a86c4122a
6 changed files with 98 additions and 48 deletions

View File

@ -81,7 +81,7 @@ pub fn parse_assembly(tree: &DataTree) -> Result<Assembly, PsyParseError> {
} }
} }
// Sphere Light // Rectangle Light
"RectangleLight" => { "RectangleLight" => {
if let &DataTree::Internal { ident: Some(ident), .. } = child { if let &DataTree::Internal { ident: Some(ident), .. } = child {
builder.add_object(ident, builder.add_object(ident,
@ -92,6 +92,17 @@ pub fn parse_assembly(tree: &DataTree) -> Result<Assembly, PsyParseError> {
} }
} }
// Surface shader
"SurfaceShader" => {
if let &DataTree::Internal { ident: Some(ident), .. } = child {
// TODO
unimplemented!()
} else {
// TODO: error condition of some kind, because no ident
panic!();
}
}
_ => { _ => {
// TODO: some kind of error, because not a known type name // TODO: some kind of error, because not a known type name
} }
@ -121,12 +132,6 @@ pub fn parse_assembly(tree: &DataTree) -> Result<Assembly, PsyParseError> {
// assembly->add_surface_shader(child.name, parse_surface_shader(child)); // assembly->add_surface_shader(child.name, parse_surface_shader(child));
// } // }
// //
//
// // Rectangle Light
// else if (child.type == "RectangleLight") {
// assembly->add_object(child.name, parse_rectangle_light(child));
// }
//
} }
} }
} else { } else {

View File

@ -286,12 +286,8 @@ impl LightPath {
// Result of shading ray, prepare light ray // Result of shading ray, prepare light ray
if self.round % 2 == 1 { if self.round % 2 == 1 {
if let &surface::SurfaceIntersection::Hit { t: _, if let &surface::SurfaceIntersection::Hit { intersection_data: idata, closure } =
incoming: _, isect {
pos,
nor,
local_space: _,
closure } = isect {
// Hit something! Do the stuff // Hit something! Do the stuff
self.interaction = *isect; // Store interaction for use in next phase self.interaction = *isect; // Store interaction for use in next phase
@ -310,7 +306,7 @@ impl LightPath {
// to the film plane if the light is not in shadow. // to the film plane if the light is not in shadow.
self.pending_color_addition = { self.pending_color_addition = {
let material = closure.as_surface_closure(); let material = closure.as_surface_closure();
let la = material.evaluate(ray.dir, shadow_vec, nor, self.wavelength); let la = material.evaluate(ray.dir, shadow_vec, idata.nor, self.wavelength);
light_color * la * self.light_attenuation / (light_pdf * light_sel_pdf) light_color * la * self.light_attenuation / (light_pdf * light_sel_pdf)
}; };
@ -318,7 +314,7 @@ impl LightPath {
// in shadow or not. // in shadow or not.
// TODO: use proper ray offsets for avoiding self-shadowing // TODO: use proper ray offsets for avoiding self-shadowing
// rather than this hacky stupid stuff. // rather than this hacky stupid stuff.
*ray = Ray::new(pos + shadow_vec.normalized() * 0.001, *ray = Ray::new(idata.pos + shadow_vec.normalized() * 0.001,
shadow_vec, shadow_vec,
self.time, self.time,
true); true);
@ -349,18 +345,14 @@ impl LightPath {
// Calculate bounced lighting! // Calculate bounced lighting!
if self.round < 6 { if self.round < 6 {
if let surface::SurfaceIntersection::Hit { t: _, if let surface::SurfaceIntersection::Hit { intersection_data: idata, closure } =
pos, self.interaction {
incoming,
nor,
local_space: _,
closure } = self.interaction {
// Sample material // Sample material
let (dir, filter, pdf) = { let (dir, filter, pdf) = {
let material = closure.as_surface_closure(); let material = closure.as_surface_closure();
let u = self.next_lds_samp(); let u = self.next_lds_samp();
let v = self.next_lds_samp(); let v = self.next_lds_samp();
material.sample(incoming, nor, (u, v), self.wavelength) material.sample(idata.incoming, idata.nor, (u, v), self.wavelength)
}; };
// Account for the additional light attenuation from // Account for the additional light attenuation from
@ -368,7 +360,7 @@ impl LightPath {
self.light_attenuation *= filter / pdf; self.light_attenuation *= filter / pdf;
// Calculate the ray for this bounce // Calculate the ray for this bounce
*ray = Ray::new(pos + dir.normalized() * 0.0001, dir, self.time, false); *ray = Ray::new(idata.pos + dir.normalized() * 0.0001, dir, self.time, false);
return true; return true;
} else { } else {

View File

@ -42,7 +42,7 @@ impl Assembly {
time: f32, time: f32,
intr: &SurfaceIntersection) intr: &SurfaceIntersection)
-> Option<(SpectralSample, Vector, f32, f32)> { -> Option<(SpectralSample, Vector, f32, f32)> {
if let &SurfaceIntersection::Hit { pos, incoming, nor, closure, .. } = intr { if let &SurfaceIntersection::Hit { intersection_data: idata, closure } = intr {
let sel_xform = if xform_stack.top().len() > 0 { let sel_xform = if xform_stack.top().len() > 0 {
lerp_slice(xform_stack.top(), time) lerp_slice(xform_stack.top(), time)
} else { } else {
@ -50,9 +50,9 @@ impl Assembly {
}; };
if let Some((light_i, sel_pdf, whittled_n)) = if let Some((light_i, sel_pdf, whittled_n)) =
self.light_accel self.light_accel
.select(incoming * sel_xform, .select(idata.incoming * sel_xform,
pos * sel_xform, idata.pos * sel_xform,
nor * sel_xform, idata.nor * sel_xform,
closure.as_surface_closure(), closure.as_surface_closure(),
time, time,
n) { n) {
@ -82,7 +82,7 @@ impl Assembly {
// Sample the light // Sample the light
let (color, shadow_vec, pdf) = let (color, shadow_vec, pdf) =
light.sample(&xform, pos, uvw.0, uvw.1, wavelength, time); light.sample(&xform, idata.pos, uvw.0, uvw.1, wavelength, time);
return Some((color, shadow_vec, pdf, sel_pdf)); return Some((color, shadow_vec, pdf, sel_pdf));
} }

View File

@ -1 +1,41 @@
pub mod surface_closure; pub mod surface_closure;
use std::fmt::Debug;
use self::surface_closure::SurfaceClosureUnion;
use surface::SurfaceIntersectionData;
/// Trait for surface shaders.
pub trait SurfaceShader: Debug {
/// Takes the result of a surface intersection and returns the surface
/// closure to be evaluated at that intersection point.
fn shade(&self, data: &SurfaceIntersectionData) -> SurfaceClosureUnion;
}
/// Clearly we must eat this brownie before the world ends, lest it
/// go uneaten before the world ends. But to do so we must trek
/// far--much like in Lord of the Rings--to fetch the golden fork with
/// which to eat the brownie. Only this fork can be used to eat this
/// brownie, for any who try to eat it with a normal fork shall
/// perish immediately and without honor. But guarding the fork are
/// three large donuts, which must all be eaten in sixty seconds or
/// less to continue on. It's called the donut challenge. But these
/// 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)]
pub struct SimpleSurfaceShader {
closure: SurfaceClosureUnion,
}
impl SimpleSurfaceShader {
fn new(closure: SurfaceClosureUnion) -> SimpleSurfaceShader {
SimpleSurfaceShader { closure: closure }
}
}
impl SurfaceShader for SimpleSurfaceShader {
fn shade(&self, data: &SurfaceIntersectionData) -> SurfaceClosureUnion {
self.closure
}
}

View File

@ -11,20 +11,6 @@ use ray::{Ray, AccelRay};
use shading::surface_closure::SurfaceClosureUnion; use shading::surface_closure::SurfaceClosureUnion;
#[derive(Debug, Copy, Clone)]
pub enum SurfaceIntersection {
Miss,
Occlude,
Hit {
t: f32,
pos: Point,
incoming: Vector,
nor: Normal,
local_space: Matrix4x4,
closure: SurfaceClosureUnion,
},
}
pub trait Surface: Boundable + Debug + Sync { pub trait Surface: Boundable + Debug + Sync {
fn intersect_rays(&self, fn intersect_rays(&self,
accel_rays: &mut [AccelRay], accel_rays: &mut [AccelRay],
@ -32,3 +18,26 @@ pub trait Surface: Boundable + Debug + Sync {
isects: &mut [SurfaceIntersection], isects: &mut [SurfaceIntersection],
space: &[Matrix4x4]); space: &[Matrix4x4]);
} }
#[derive(Debug, Copy, Clone)]
pub enum SurfaceIntersection {
Miss,
Occlude,
Hit {
intersection_data: SurfaceIntersectionData,
closure: SurfaceClosureUnion,
},
}
#[derive(Debug, Copy, Clone)]
pub struct SurfaceIntersectionData {
pub incoming: Vector, // Direction of the incoming ray
pub t: f32, // Ray t-value at the intersection point
pub pos: Point, // Position of the intersection
pub nor: Normal, // Shading normal
pub nor_g: Normal, // True geometric normal
pub uv: (f32, f32), // 2d surface parameters
pub local_space: Matrix4x4, // Matrix from global space to local space
}

View File

@ -9,7 +9,7 @@ use math::{Point, Matrix4x4, cross};
use ray::{Ray, AccelRay}; use ray::{Ray, AccelRay};
use shading::surface_closure::{SurfaceClosureUnion, GTRClosure}; use shading::surface_closure::{SurfaceClosureUnion, GTRClosure};
use super::{Surface, SurfaceIntersection}; use super::{Surface, SurfaceIntersection, SurfaceIntersectionData};
use super::triangle; use super::triangle;
@ -92,11 +92,15 @@ impl Surface for TriangleMesh {
r.mark_done(); r.mark_done();
} else { } else {
isects[r.id as usize] = SurfaceIntersection::Hit { isects[r.id as usize] = SurfaceIntersection::Hit {
t: t, intersection_data: SurfaceIntersectionData {
pos: wr.orig + (wr.dir * t), incoming: wr.dir,
incoming: wr.dir, t: t,
nor: cross(tri.0 - tri.1, tri.0 - tri.2).into_normal(), pos: wr.orig + (wr.dir * t),
local_space: mat_space, nor: cross(tri.0 - tri.1, tri.0 - tri.2).into_normal(), // TODO
nor_g: cross(tri.0 - tri.1, tri.0 - tri.2).into_normal(),
uv: (0.0, 0.0), // TODO
local_space: mat_space,
},
// TODO: get surface closure from surface shader. // TODO: get surface closure from surface shader.
//closure: SurfaceClosureUnion::LambertClosure( //closure: SurfaceClosureUnion::LambertClosure(
// LambertClosure::new(XYZ::new(0.8, 0.8, 0.8)) // LambertClosure::new(XYZ::new(0.8, 0.8, 0.8))