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 float4::Float4;
use lerp::Lerp;
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 {
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, 2)),
self.sample_spectrum(nth_wavelength(hero_wavelength, 3))],
self.sample_spectrum(nth_wavelength(hero_wavelength, 3))),
hero_wavelength: hero_wavelength,
}
@ -42,7 +43,7 @@ fn nth_wavelength(hero_wavelength: f32, n: usize) -> f32 {
#[derive(Copy, Clone, Debug)]
pub struct SpectralSample {
e: [f32; 4],
e: Float4,
hero_wavelength: f32,
}
@ -50,7 +51,15 @@ impl SpectralSample {
pub fn new(wavelength: f32) -> SpectralSample {
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
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,
}
}
@ -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)]
pub struct XYZ {

View File

@ -88,6 +88,22 @@ impl Float4 {
*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 light::{SphereLight, RectangleLight};
use color::XYZ;
use color::{XYZ, rec709e_to_xyz};
pub fn parse_sphere_light(tree: &DataTree) -> Result<SphereLight, PsyParseError> {
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.
// Probably will need a special color type with its
// own parser...?
colors.push(XYZ::new(color.0, color.1, color.2));
colors.push(XYZ::from_tuple(rec709e_to_xyz(color)));
} else {
// Found color, but its contents is not in the right format
return Err(PsyParseError::UnknownError);
@ -81,7 +81,7 @@ pub fn parse_rectangle_light(tree: &DataTree) -> Result<RectangleLight, PsyParse
// TODO: handle color space conversions properly.
// Probably will need a special color type with its
// own parser...?
colors.push(XYZ::new(color.0, color.1, color.2));
colors.push(XYZ::from_tuple(rec709e_to_xyz(color)));
} else {
// Found color, but its contents is not in the right format
return Err(PsyParseError::UnknownError);

View File

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