Multiple light sources are now handled.

This commit is contained in:
Nathan Vegdahl 2016-07-10 00:10:49 -07:00
parent 9c8797ffd8
commit 5df583c2d0
5 changed files with 118 additions and 42 deletions

View File

@ -1,10 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use math::Matrix4x4; use math::{Matrix4x4, Vector};
use lerp::lerp_slice;
use bvh::BVH; use bvh::BVH;
use light_accel::{LightAccel, LightArray};
use boundable::Boundable; use boundable::Boundable;
use surface::Surface; use surface::{Surface, SurfaceIntersection};
use light::LightSource; use light::LightSource;
use color::SpectralSample;
use bbox::{BBox, transform_bbox_slice_from}; use bbox::{BBox, transform_bbox_slice_from};
@ -12,6 +15,7 @@ use bbox::{BBox, transform_bbox_slice_from};
pub struct Assembly { pub struct Assembly {
// Instance list // Instance list
pub instances: Vec<Instance>, pub instances: Vec<Instance>,
pub light_instances: Vec<Instance>,
pub xforms: Vec<Matrix4x4>, pub xforms: Vec<Matrix4x4>,
// Object list // Object list
@ -24,7 +28,51 @@ pub struct Assembly {
pub object_accel: BVH, pub object_accel: BVH,
// Light accel // Light accel
pub light_accel: Vec<Instance>, pub light_accel: LightArray,
}
impl Assembly {
// Returns (light_color, shadow_vector, selection_pdf)
pub fn sample_lights(&self,
n: f32,
uvw: (f32, f32, f32),
wavelength: f32,
time: f32,
intr: &SurfaceIntersection)
-> Option<(SpectralSample, Vector, f32)> {
if let &SurfaceIntersection::Hit { pos, .. } = intr {
if let Some((light_i, sel_pdf, _)) = self.light_accel.select(n) {
let inst = self.light_instances[light_i];
match inst.instance_type {
InstanceType::Object => {
match &self.objects[inst.data_index] {
&Object::Light(ref light) => {
let xform = if let Some((a, b)) = inst.transform_indices {
lerp_slice(&self.xforms[a..b], time)
} else {
Matrix4x4::new()
};
let (color, shadow_vec, pdf) =
light.sample(&xform, pos, uvw.0, uvw.1, wavelength, time);
return Some((color, shadow_vec, pdf * sel_pdf));
}
_ => unimplemented!(),
}
}
InstanceType::Assembly => {
// TODO: recursive light selection inside assemblies
unimplemented!()
}
}
} else {
None
}
} else {
None
}
}
} }
impl Boundable for Assembly { impl Boundable for Assembly {
@ -151,21 +199,24 @@ impl AssemblyBuilder {
println!("Assembly BVH Depth: {}", object_accel.tree_depth()); println!("Assembly BVH Depth: {}", object_accel.tree_depth());
// Build light accel // Build light accel
// TODO: build light tree instead of stupid vec let mut light_instances = self.instances.clone();
let light_accel = { let light_accel = LightArray::new(&mut light_instances[..], |inst| {
let mut light_accel = Vec::new(); match inst.instance_type {
for inst in self.instances.iter() { InstanceType::Object => {
if let InstanceType::Object = inst.instance_type {
if let Object::Light(_) = self.objects[inst.data_index] { if let Object::Light(_) = self.objects[inst.data_index] {
light_accel.push(*inst); Some((&bbs[bis[inst.id]..bis[inst.id + 1]], 1.0))
} else {
None
} }
} }
_ => None,
} }
light_accel });
};
Assembly { Assembly {
instances: self.instances, instances: self.instances,
light_instances: light_instances,
xforms: self.xforms, xforms: self.xforms,
objects: self.objects, objects: self.objects,
assemblies: self.assemblies, assemblies: self.assemblies,

50
src/light_accel/mod.rs Normal file
View File

@ -0,0 +1,50 @@
use bbox::BBox;
pub trait LightAccel {
/// Returns (index_of_light, selection_pdf, whittled_n)
fn select(&self, n: f32) -> Option<(usize, f32, f32)>;
}
#[derive(Debug, Clone)]
pub struct LightArray {
indices: Vec<usize>,
}
impl LightArray {
pub fn new<'a, T, F>(things: &mut [T], q: F) -> LightArray
where F: 'a + Fn(&T) -> Option<(&'a [BBox], f32)>
{
let mut indices = Vec::new();
for (i, thing) in things.iter().enumerate() {
if let Some((_, power)) = q(thing) {
if power > 0.0 {
indices.push(i);
}
}
}
LightArray { indices: indices }
}
}
impl LightAccel for LightArray {
fn select(&self, n: f32) -> Option<(usize, f32, f32)> {
assert!(n >= 0.0 && n <= 1.0);
if self.indices.len() == 0 {
return None;
}
let n2 = n * self.indices.len() as f32;
let i = if n == 1.0 {
*self.indices.last().unwrap()
} else {
self.indices[n2 as usize]
};
let whittled_n = n2 - i as f32;
let pdf = 1.0 / self.indices.len() as f32;
Some((i, pdf, whittled_n))
}
}

View File

@ -22,6 +22,7 @@ mod triangle;
mod surface; mod surface;
mod light; mod light;
mod bvh; mod bvh;
mod light_accel;
mod scene; mod scene;
mod assembly; mod assembly;
mod halton; mod halton;

View File

@ -1,7 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::result::Result; use std::result::Result;
use std::cmp::Eq;
use std::iter::Iterator; use std::iter::Iterator;
use std::slice; use std::slice;

View File

@ -2,23 +2,19 @@
use std::path::Path; use std::path::Path;
use std::cmp::min; use std::cmp::min;
use std::iter::Iterator;
use std::sync::RwLock; use std::sync::RwLock;
use scoped_threadpool::Pool; use scoped_threadpool::Pool;
use crossbeam::sync::MsQueue; use crossbeam::sync::MsQueue;
use algorithm::partition_pair; use algorithm::partition_pair;
use lerp::lerp_slice;
use ray::Ray; use ray::Ray;
use assembly::Object;
use tracer::Tracer; use tracer::Tracer;
use halton; use halton;
use math::{Matrix4x4, fast_logit}; use math::fast_logit;
use image::Image; use image::Image;
use surface; use surface;
use scene::Scene; use scene::Scene;
use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength}; use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength};
use shading::surface_closure::{SurfaceClosure, LambertClosure};
#[derive(Debug)] #[derive(Debug)]
pub struct Renderer { pub struct Renderer {
@ -239,31 +235,10 @@ impl LightPath {
self.interaction = *isect; // Store interaction for use in next phase self.interaction = *isect; // Store interaction for use in next phase
// Prepare light ray // Prepare light ray
if scene.root.light_accel.len() > 0 { let light_n = self.next_lds_samp();
// Get the light and the mapping to its local space let light_uvw = (self.next_lds_samp(), self.next_lds_samp(), self.next_lds_samp());
let (light, space) = { if let Some((light_color, shadow_vec, light_pdf)) = scene.root
let l1 = &scene.root.objects[scene.root.light_accel[0].data_index]; .sample_lights(light_n, light_uvw, self.wavelength, self.time, isect) {
let light = if let &Object::Light(ref light) = l1 {
light
} else {
panic!()
};
let space = if let Some((start, end)) = scene.root.light_accel[0]
.transform_indices {
lerp_slice(&scene.root.xforms[start..end], self.time)
} else {
Matrix4x4::new()
};
(light, space)
};
// Sample the light
let (light_color, shadow_vec, light_pdf) = {
let lu = self.next_lds_samp();
let lv = self.next_lds_samp();
light.sample(&space, pos, lu, lv, self.wavelength, self.time)
};
// Calculate and store the light that will be contributed // Calculate and store the light that will be contributed
// to the film plane if the light is not in shadow. // to the film plane if the light is not in shadow.
self.pending_color_addition = { self.pending_color_addition = {