Implemented ray intersection for RectangleLights.
This means that RectangleLights now work with MIS. Yay!
This commit is contained in:
parent
072d366892
commit
81c8da8113
|
@ -4,11 +4,12 @@ use bbox::BBox;
|
|||
use boundable::Boundable;
|
||||
use color::{XYZ, SpectralSample, Color};
|
||||
use lerp::lerp_slice;
|
||||
use math::{Vector, Normal, Point, Matrix4x4};
|
||||
use math::{Vector, Normal, Point, Matrix4x4, cross};
|
||||
use ray::{Ray, AccelRay};
|
||||
use sampling::{spherical_triangle_solid_angle, uniform_sample_spherical_triangle};
|
||||
use shading::surface_closure::{SurfaceClosureUnion, EmitClosure};
|
||||
use shading::SurfaceShader;
|
||||
use surface::{Surface, SurfaceIntersection};
|
||||
use surface::{Surface, SurfaceIntersection, SurfaceIntersectionData, triangle};
|
||||
|
||||
use super::SurfaceLight;
|
||||
|
||||
|
@ -42,41 +43,43 @@ impl<'a> RectangleLight<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// fn sample_pdf(
|
||||
// &self,
|
||||
// space: &Matrix4x4,
|
||||
// arr: Point,
|
||||
// sample_dir: Vector,
|
||||
// sample_u: f32,
|
||||
// sample_v: f32,
|
||||
// wavelength: f32,
|
||||
// time: f32,
|
||||
// ) -> f32 {
|
||||
// // We're not using these, silence warnings
|
||||
// let _ = (sample_dir, sample_u, sample_v, wavelength);
|
||||
// TODO: this is only used from within `intersect_rays`, and could be done
|
||||
// more efficiently by inlining it there.
|
||||
fn sample_pdf(
|
||||
&self,
|
||||
space: &Matrix4x4,
|
||||
arr: Point,
|
||||
sample_dir: Vector,
|
||||
sample_u: f32,
|
||||
sample_v: f32,
|
||||
wavelength: f32,
|
||||
time: f32,
|
||||
) -> 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
|
||||
// let space_inv = space.inverse();
|
||||
// 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;
|
||||
// Get the four corners of the rectangle, transformed into world space
|
||||
let space_inv = space.inverse();
|
||||
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;
|
||||
|
||||
// // Get the four corners of the rectangle, projected on to the unit
|
||||
// // sphere centered around arr.
|
||||
// let sp1 = (p1 - arr).normalized();
|
||||
// let sp2 = (p2 - arr).normalized();
|
||||
// let sp3 = (p3 - arr).normalized();
|
||||
// let sp4 = (p4 - arr).normalized();
|
||||
// Get the four corners of the rectangle, projected on to the unit
|
||||
// sphere centered around arr.
|
||||
let sp1 = (p1 - arr).normalized();
|
||||
let sp2 = (p2 - arr).normalized();
|
||||
let sp3 = (p3 - arr).normalized();
|
||||
let sp4 = (p4 - arr).normalized();
|
||||
|
||||
// // Get the solid angles of the rectangle split into two triangles
|
||||
// let area_1 = spherical_triangle_solid_angle(sp2, sp1, sp3);
|
||||
// let area_2 = spherical_triangle_solid_angle(sp4, sp1, sp3);
|
||||
// Get the solid angles of the rectangle split into two triangles
|
||||
let area_1 = spherical_triangle_solid_angle(sp2, 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(
|
||||
// &self,
|
||||
|
@ -114,7 +117,6 @@ impl<'a> SurfaceLight for RectangleLight<'a> {
|
|||
let dim = lerp_slice(self.dimensions, 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);
|
||||
|
||||
// Get the four corners of the rectangle, transformed into world space
|
||||
|
@ -196,9 +198,77 @@ impl<'a> Surface for RectangleLight<'a> {
|
|||
shader: &SurfaceShader,
|
||||
space: &[Matrix4x4],
|
||||
) {
|
||||
let _ = (accel_rays, wrays, isects, shader, space);
|
||||
// TODO
|
||||
// unimplemented!()
|
||||
let _ = shader; // Silence 'unused' warning
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
mod triangle;
|
||||
pub mod triangle;
|
||||
pub mod triangle_mesh;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
|
Loading…
Reference in New Issue
Block a user