Implemented ray intersection for RectangleLights.

This means that RectangleLights now work with MIS.  Yay!
This commit is contained in:
Nathan Vegdahl 2017-08-17 13:46:38 -07:00
parent 072d366892
commit 81c8da8113
2 changed files with 107 additions and 37 deletions

View File

@ -4,11 +4,12 @@ use bbox::BBox;
use boundable::Boundable; use boundable::Boundable;
use color::{XYZ, SpectralSample, Color}; use color::{XYZ, SpectralSample, Color};
use lerp::lerp_slice; use lerp::lerp_slice;
use math::{Vector, Normal, Point, Matrix4x4}; use math::{Vector, Normal, Point, Matrix4x4, cross};
use ray::{Ray, AccelRay}; use ray::{Ray, AccelRay};
use sampling::{spherical_triangle_solid_angle, uniform_sample_spherical_triangle}; use sampling::{spherical_triangle_solid_angle, uniform_sample_spherical_triangle};
use shading::surface_closure::{SurfaceClosureUnion, EmitClosure};
use shading::SurfaceShader; use shading::SurfaceShader;
use surface::{Surface, SurfaceIntersection}; use surface::{Surface, SurfaceIntersection, SurfaceIntersectionData, triangle};
use super::SurfaceLight; use super::SurfaceLight;
@ -42,41 +43,43 @@ impl<'a> RectangleLight<'a> {
} }
} }
// fn sample_pdf( // TODO: this is only used from within `intersect_rays`, and could be done
// &self, // more efficiently by inlining it there.
// space: &Matrix4x4, fn sample_pdf(
// arr: Point, &self,
// sample_dir: Vector, space: &Matrix4x4,
// sample_u: f32, arr: Point,
// sample_v: f32, sample_dir: Vector,
// wavelength: f32, sample_u: f32,
// time: f32, sample_v: f32,
// ) -> f32 { wavelength: f32,
// // We're not using these, silence warnings time: f32,
// let _ = (sample_dir, sample_u, sample_v, wavelength); ) -> f32 {
// We're not using these, silence warnings
let _ = (sample_dir, sample_u, sample_v, wavelength);
// let dim = lerp_slice(self.dimensions, time); let dim = lerp_slice(self.dimensions, time);
// // Get the four corners of the rectangle, transformed into world space // Get the four corners of the rectangle, transformed into world space
// let space_inv = space.inverse(); let space_inv = space.inverse();
// let p1 = Point::new(dim.0 * 0.5, dim.1 * 0.5, 0.0) * space_inv; let p1 = Point::new(dim.0 * 0.5, dim.1 * 0.5, 0.0) * space_inv;
// let p2 = Point::new(dim.0 * -0.5, dim.1 * 0.5, 0.0) * space_inv; let p2 = Point::new(dim.0 * -0.5, dim.1 * 0.5, 0.0) * space_inv;
// let p3 = Point::new(dim.0 * -0.5, dim.1 * -0.5, 0.0) * space_inv; let p3 = Point::new(dim.0 * -0.5, dim.1 * -0.5, 0.0) * space_inv;
// let p4 = Point::new(dim.0 * 0.5, dim.1 * -0.5, 0.0) * space_inv; let p4 = Point::new(dim.0 * 0.5, dim.1 * -0.5, 0.0) * space_inv;
// // Get the four corners of the rectangle, projected on to the unit // Get the four corners of the rectangle, projected on to the unit
// // sphere centered around arr. // sphere centered around arr.
// let sp1 = (p1 - arr).normalized(); let sp1 = (p1 - arr).normalized();
// let sp2 = (p2 - arr).normalized(); let sp2 = (p2 - arr).normalized();
// let sp3 = (p3 - arr).normalized(); let sp3 = (p3 - arr).normalized();
// let sp4 = (p4 - arr).normalized(); let sp4 = (p4 - arr).normalized();
// // Get the solid angles of the rectangle split into two triangles // Get the solid angles of the rectangle split into two triangles
// let area_1 = spherical_triangle_solid_angle(sp2, sp1, sp3); let area_1 = spherical_triangle_solid_angle(sp2, sp1, sp3);
// let area_2 = spherical_triangle_solid_angle(sp4, sp1, sp3); let area_2 = spherical_triangle_solid_angle(sp4, sp1, sp3);
// 1.0 / (area_1 + area_2) 1.0 / (area_1 + area_2)
// } }
// fn outgoing( // fn outgoing(
// &self, // &self,
@ -114,7 +117,6 @@ impl<'a> SurfaceLight for RectangleLight<'a> {
let dim = lerp_slice(self.dimensions, time); let dim = lerp_slice(self.dimensions, time);
let col = lerp_slice(self.colors, time); let col = lerp_slice(self.colors, time);
// TODO: Is this right? Do we need to get the surface area post-transform?
let surface_area_inv: f64 = 1.0 / (dim.0 as f64 * dim.1 as f64); let surface_area_inv: f64 = 1.0 / (dim.0 as f64 * dim.1 as f64);
// Get the four corners of the rectangle, transformed into world space // Get the four corners of the rectangle, transformed into world space
@ -196,9 +198,77 @@ impl<'a> Surface for RectangleLight<'a> {
shader: &SurfaceShader, shader: &SurfaceShader,
space: &[Matrix4x4], space: &[Matrix4x4],
) { ) {
let _ = (accel_rays, wrays, isects, shader, space); let _ = shader; // Silence 'unused' warning
// TODO
// unimplemented!() for r in accel_rays.iter_mut() {
let wr = &wrays[r.id as usize];
// Calculate time interpolated values
let dim = lerp_slice(self.dimensions, r.time);
let xform = lerp_slice(space, r.time);
let space_inv = xform.inverse();
// Get the four corners of the rectangle, transformed into world space
let p1 = Point::new(dim.0 * 0.5, dim.1 * 0.5, 0.0) * space_inv;
let p2 = Point::new(dim.0 * -0.5, dim.1 * 0.5, 0.0) * space_inv;
let p3 = Point::new(dim.0 * -0.5, dim.1 * -0.5, 0.0) * space_inv;
let p4 = Point::new(dim.0 * 0.5, dim.1 * -0.5, 0.0) * space_inv;
// Test against two triangles that make up the light
for tri in &[(p1, p2, p3), (p3, p4, p1)] {
if let Some((t, b0, b1, b2)) = triangle::intersect_ray(wr, *tri) {
if t < r.max_t {
if r.is_occlusion() {
isects[r.id as usize] = SurfaceIntersection::Occlude;
r.mark_done();
} else {
let (pos, pos_err) = triangle::surface_point(*tri, (b0, b1, b2));
let normal = cross(tri.0 - tri.1, tri.0 - tri.2).into_normal();
let intersection_data = SurfaceIntersectionData {
incoming: wr.dir,
t: t,
pos: pos,
pos_err: pos_err,
nor: normal,
nor_g: normal,
uv: (0.0, 0.0), // TODO
local_space: xform,
sample_pdf: self.sample_pdf(
&xform,
wr.orig,
wr.dir,
0.0,
0.0,
wr.wavelength,
r.time,
),
};
let closure = {
let inv_surface_area = (1.0 / (dim.0 as f64 * dim.1 as f64)) as f32;
let color = lerp_slice(self.colors, r.time).to_spectral_sample(
wr.wavelength,
) * inv_surface_area;
SurfaceClosureUnion::EmitClosure(EmitClosure::new(color))
};
// Fill in intersection
isects[r.id as usize] = SurfaceIntersection::Hit {
intersection_data: intersection_data,
closure: closure,
};
// Set ray's max t
r.max_t = t;
}
break;
}
}
}
}
} }
} }

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
mod triangle; pub mod triangle;
pub mod triangle_mesh; pub mod triangle_mesh;
use std::fmt::Debug; use std::fmt::Debug;