More proper use of light sources.

This commit is contained in:
Nathan Vegdahl 2016-07-01 00:00:38 -07:00
parent 24cbdb5ab9
commit 02a0740cac
4 changed files with 97 additions and 21 deletions

View File

@ -2,6 +2,7 @@ mod spectra_xyz;
use std::ops::{Add, AddAssign, Mul, MulAssign, Div, DivAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign, Div, DivAssign};
use float4::Float4;
use lerp::Lerp; use lerp::Lerp;
use self::spectra_xyz::{spectrum_xyz_to_p, EQUAL_ENERGY_REFLECTANCE}; use self::spectra_xyz::{spectrum_xyz_to_p, EQUAL_ENERGY_REFLECTANCE};
@ -20,10 +21,10 @@ pub trait Color {
fn to_spectral_sample(&self, hero_wavelength: f32) -> SpectralSample { fn to_spectral_sample(&self, hero_wavelength: f32) -> SpectralSample {
SpectralSample { SpectralSample {
e: [self.sample_spectrum(nth_wavelength(hero_wavelength, 0)), e: Float4::new(self.sample_spectrum(nth_wavelength(hero_wavelength, 0)),
self.sample_spectrum(nth_wavelength(hero_wavelength, 1)), self.sample_spectrum(nth_wavelength(hero_wavelength, 1)),
self.sample_spectrum(nth_wavelength(hero_wavelength, 2)), self.sample_spectrum(nth_wavelength(hero_wavelength, 2)),
self.sample_spectrum(nth_wavelength(hero_wavelength, 3))], self.sample_spectrum(nth_wavelength(hero_wavelength, 3))),
hero_wavelength: hero_wavelength, hero_wavelength: hero_wavelength,
} }
@ -42,7 +43,7 @@ fn nth_wavelength(hero_wavelength: f32, n: usize) -> f32 {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct SpectralSample { pub struct SpectralSample {
e: [f32; 4], e: Float4,
hero_wavelength: f32, hero_wavelength: f32,
} }
@ -50,7 +51,15 @@ impl SpectralSample {
pub fn new(wavelength: f32) -> SpectralSample { pub fn new(wavelength: f32) -> SpectralSample {
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX); debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
SpectralSample { SpectralSample {
e: [0.0; 4], e: Float4::new(0.0, 0.0, 0.0, 0.0),
hero_wavelength: wavelength,
}
}
pub fn from_value(value: f32, wavelength: f32) -> SpectralSample {
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
SpectralSample {
e: Float4::new(value, value, value, value),
hero_wavelength: wavelength, hero_wavelength: wavelength,
} }
} }
@ -66,6 +75,56 @@ impl SpectralSample {
} }
} }
impl Add for SpectralSample {
type Output = SpectralSample;
fn add(self, rhs: SpectralSample) -> Self::Output {
assert!(self.hero_wavelength == rhs.hero_wavelength);
SpectralSample {
e: self.e + rhs.e,
hero_wavelength: self.hero_wavelength,
}
}
}
impl AddAssign for SpectralSample {
fn add_assign(&mut self, rhs: SpectralSample) {
assert!(self.hero_wavelength == rhs.hero_wavelength);
self.e = self.e + rhs.e;
}
}
impl Mul<f32> for SpectralSample {
type Output = SpectralSample;
fn mul(self, rhs: f32) -> Self::Output {
SpectralSample {
e: self.e * rhs,
hero_wavelength: self.hero_wavelength,
}
}
}
impl MulAssign<f32> for SpectralSample {
fn mul_assign(&mut self, rhs: f32) {
self.e = self.e * rhs;
}
}
impl Div<f32> for SpectralSample {
type Output = SpectralSample;
fn div(self, rhs: f32) -> Self::Output {
SpectralSample {
e: self.e / rhs,
hero_wavelength: self.hero_wavelength,
}
}
}
impl DivAssign<f32> for SpectralSample {
fn div_assign(&mut self, rhs: f32) {
self.e = self.e / rhs;
}
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct XYZ { pub struct XYZ {

View File

@ -88,6 +88,22 @@ impl Float4 {
*self.data.get_unchecked_mut(3) = n; *self.data.get_unchecked_mut(3) = n;
} }
} }
pub fn get_0(&self) -> f32 {
unsafe { *self.data.get_unchecked(0) }
}
pub fn get_1(&self) -> f32 {
unsafe { *self.data.get_unchecked(1) }
}
pub fn get_2(&self) -> f32 {
unsafe { *self.data.get_unchecked(2) }
}
pub fn get_3(&self) -> f32 {
unsafe { *self.data.get_unchecked(3) }
}
} }

View File

@ -9,7 +9,7 @@ use super::basics::ws_f32;
use super::psy::PsyParseError; use super::psy::PsyParseError;
use light::{SphereLight, RectangleLight}; use light::{SphereLight, RectangleLight};
use color::XYZ; use color::{XYZ, rec709e_to_xyz};
pub fn parse_sphere_light(tree: &DataTree) -> Result<SphereLight, PsyParseError> { pub fn parse_sphere_light(tree: &DataTree) -> Result<SphereLight, PsyParseError> {
if let &DataTree::Internal { ref children, .. } = tree { if let &DataTree::Internal { ref children, .. } = tree {
@ -37,7 +37,7 @@ pub fn parse_sphere_light(tree: &DataTree) -> Result<SphereLight, PsyParseError>
// TODO: handle color space conversions properly. // TODO: handle color space conversions properly.
// Probably will need a special color type with its // Probably will need a special color type with its
// own parser...? // own parser...?
colors.push(XYZ::new(color.0, color.1, color.2)); colors.push(XYZ::from_tuple(rec709e_to_xyz(color)));
} else { } else {
// Found color, but its contents is not in the right format // Found color, but its contents is not in the right format
return Err(PsyParseError::UnknownError); return Err(PsyParseError::UnknownError);
@ -81,7 +81,7 @@ pub fn parse_rectangle_light(tree: &DataTree) -> Result<RectangleLight, PsyParse
// TODO: handle color space conversions properly. // TODO: handle color space conversions properly.
// Probably will need a special color type with its // Probably will need a special color type with its
// own parser...? // own parser...?
colors.push(XYZ::new(color.0, color.1, color.2)); colors.push(XYZ::from_tuple(rec709e_to_xyz(color)));
} else { } else {
// Found color, but its contents is not in the right format // Found color, but its contents is not in the right format
return Err(PsyParseError::UnknownError); return Err(PsyParseError::UnknownError);

View File

@ -18,7 +18,7 @@ use math::{Matrix4x4, dot, fast_logit};
use image::Image; use image::Image;
use surface; use surface;
use scene::Scene; use scene::Scene;
use color::{Color, XYZ, map_0_1_to_wavelength}; use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength};
#[derive(Debug)] #[derive(Debug)]
pub struct Renderer { pub struct Renderer {
@ -139,7 +139,7 @@ impl Renderer {
for path in paths.iter() { for path in paths.iter() {
let mut col = let mut col =
img.get(path.pixel_co.0 as usize, path.pixel_co.1 as usize); img.get(path.pixel_co.0 as usize, path.pixel_co.1 as usize);
col += path.color / self.spp as f32; col += XYZ::from_spectral_sample(&path.color) / self.spp as f32;
img.set(path.pixel_co.0 as usize, path.pixel_co.1 as usize, col); img.set(path.pixel_co.0 as usize, path.pixel_co.1 as usize, col);
} }
} }
@ -188,8 +188,9 @@ pub struct LightPath {
round: u32, round: u32,
time: f32, time: f32,
wavelength: f32, wavelength: f32,
light_attenuation: XYZ, light_attenuation: SpectralSample,
color: XYZ, pending_color_addition: SpectralSample,
color: SpectralSample,
} }
impl LightPath { impl LightPath {
@ -208,8 +209,9 @@ impl LightPath {
round: 0, round: 0,
time: time, time: time,
wavelength: wavelength, wavelength: wavelength,
light_attenuation: XYZ::new(1.0, 1.0, 1.0), light_attenuation: SpectralSample::from_value(1.0, wavelength),
color: XYZ::new(0.0, 0.0, 0.0), pending_color_addition: SpectralSample::new(wavelength),
color: SpectralSample::new(wavelength),
}, },
scene.camera.generate_ray(image_plane_co.0, scene.camera.generate_ray(image_plane_co.0,
@ -257,7 +259,7 @@ impl LightPath {
let lu = self.next_lds_samp(); let lu = self.next_lds_samp();
let lv = self.next_lds_samp(); let lv = self.next_lds_samp();
// TODO: store incident light info and pdf, and use them properly // TODO: store incident light info and pdf, and use them properly
let (_, shadow_vec, _) = let (light_color, shadow_vec, light_pdf) =
light.sample(&space, pos, lu, lv, self.wavelength, self.time); light.sample(&space, pos, lu, lv, self.wavelength, self.time);
let rnor = if dot(nor.into_vector(), ray.dir) > 0.0 { let rnor = if dot(nor.into_vector(), ray.dir) > 0.0 {
@ -266,8 +268,8 @@ impl LightPath {
nor.into_vector().normalized() nor.into_vector().normalized()
}; };
let la = dot(rnor, shadow_vec.normalized()).max(0.0); let la = dot(rnor, shadow_vec.normalized()).max(0.0);
self.light_attenuation = XYZ::from_spectral_sample(&XYZ::new(la, la, la) // self.light_attenuation = SpectralSample::from_value(la);
.to_spectral_sample(self.wavelength)); self.pending_color_addition = light_color * la / light_pdf;
*ray = Ray::new(pos + rnor * 0.0001, *ray = Ray::new(pos + rnor * 0.0001,
shadow_vec - rnor * 0.0001, shadow_vec - rnor * 0.0001,
self.time, self.time,
@ -280,8 +282,7 @@ impl LightPath {
} else { } else {
// Didn't hit anything, so background color // Didn't hit anything, so background color
let xyz = XYZ::new(0.02, 0.02, 0.02); let xyz = XYZ::new(0.02, 0.02, 0.02);
self.color += self.color += xyz.to_spectral_sample(self.wavelength);
XYZ::from_spectral_sample(&xyz.to_spectral_sample(self.wavelength));
return false; return false;
} }
@ -291,7 +292,7 @@ impl LightPath {
1 => { 1 => {
self.round += 1; self.round += 1;
if let &surface::SurfaceIntersection::Miss = isect { if let &surface::SurfaceIntersection::Miss = isect {
self.color += self.light_attenuation; self.color += self.pending_color_addition;
} }
return false; return false;
} }