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" => {
if let &DataTree::Internal { ident: Some(ident), .. } = child {
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
}
@ -121,12 +132,6 @@ pub fn parse_assembly(tree: &DataTree) -> Result<Assembly, PsyParseError> {
// 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 {

View File

@ -286,12 +286,8 @@ impl LightPath {
// Result of shading ray, prepare light ray
if self.round % 2 == 1 {
if let &surface::SurfaceIntersection::Hit { t: _,
incoming: _,
pos,
nor,
local_space: _,
closure } = isect {
if let &surface::SurfaceIntersection::Hit { intersection_data: idata, closure } =
isect {
// Hit something! Do the stuff
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.
self.pending_color_addition = {
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)
};
@ -318,7 +314,7 @@ impl LightPath {
// in shadow or not.
// TODO: use proper ray offsets for avoiding self-shadowing
// 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,
self.time,
true);
@ -349,18 +345,14 @@ impl LightPath {
// Calculate bounced lighting!
if self.round < 6 {
if let surface::SurfaceIntersection::Hit { t: _,
pos,
incoming,
nor,
local_space: _,
closure } = self.interaction {
if let surface::SurfaceIntersection::Hit { intersection_data: idata, closure } =
self.interaction {
// Sample material
let (dir, filter, pdf) = {
let material = closure.as_surface_closure();
let u = 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
@ -368,7 +360,7 @@ impl LightPath {
self.light_attenuation *= filter / pdf;
// 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;
} else {

View File

@ -42,7 +42,7 @@ impl Assembly {
time: f32,
intr: &SurfaceIntersection)
-> 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 {
lerp_slice(xform_stack.top(), time)
} else {
@ -50,9 +50,9 @@ impl Assembly {
};
if let Some((light_i, sel_pdf, whittled_n)) =
self.light_accel
.select(incoming * sel_xform,
pos * sel_xform,
nor * sel_xform,
.select(idata.incoming * sel_xform,
idata.pos * sel_xform,
idata.nor * sel_xform,
closure.as_surface_closure(),
time,
n) {
@ -82,7 +82,7 @@ impl Assembly {
// Sample the light
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));
}

View File

@ -1 +1,41 @@
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;
#[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 {
fn intersect_rays(&self,
accel_rays: &mut [AccelRay],
@ -32,3 +18,26 @@ pub trait Surface: Boundable + Debug + Sync {
isects: &mut [SurfaceIntersection],
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 shading::surface_closure::{SurfaceClosureUnion, GTRClosure};
use super::{Surface, SurfaceIntersection};
use super::{Surface, SurfaceIntersection, SurfaceIntersectionData};
use super::triangle;
@ -92,11 +92,15 @@ impl Surface for TriangleMesh {
r.mark_done();
} else {
isects[r.id as usize] = SurfaceIntersection::Hit {
t: t,
pos: wr.orig + (wr.dir * t),
incoming: wr.dir,
nor: cross(tri.0 - tri.1, tri.0 - tri.2).into_normal(),
local_space: mat_space,
intersection_data: SurfaceIntersectionData {
incoming: wr.dir,
t: t,
pos: wr.orig + (wr.dir * t),
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.
//closure: SurfaceClosureUnion::LambertClosure(
// LambertClosure::new(XYZ::new(0.8, 0.8, 0.8))