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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user