Multiple light sources are now handled.
This commit is contained in:
parent
9c8797ffd8
commit
5df583c2d0
|
@ -1,10 +1,13 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use math::Matrix4x4;
|
||||
use math::{Matrix4x4, Vector};
|
||||
use lerp::lerp_slice;
|
||||
use bvh::BVH;
|
||||
use light_accel::{LightAccel, LightArray};
|
||||
use boundable::Boundable;
|
||||
use surface::Surface;
|
||||
use surface::{Surface, SurfaceIntersection};
|
||||
use light::LightSource;
|
||||
use color::SpectralSample;
|
||||
use bbox::{BBox, transform_bbox_slice_from};
|
||||
|
||||
|
||||
|
@ -12,6 +15,7 @@ use bbox::{BBox, transform_bbox_slice_from};
|
|||
pub struct Assembly {
|
||||
// Instance list
|
||||
pub instances: Vec<Instance>,
|
||||
pub light_instances: Vec<Instance>,
|
||||
pub xforms: Vec<Matrix4x4>,
|
||||
|
||||
// Object list
|
||||
|
@ -24,7 +28,51 @@ pub struct Assembly {
|
|||
pub object_accel: BVH,
|
||||
|
||||
// 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 {
|
||||
|
@ -151,21 +199,24 @@ impl AssemblyBuilder {
|
|||
println!("Assembly BVH Depth: {}", object_accel.tree_depth());
|
||||
|
||||
// Build light accel
|
||||
// TODO: build light tree instead of stupid vec
|
||||
let light_accel = {
|
||||
let mut light_accel = Vec::new();
|
||||
for inst in self.instances.iter() {
|
||||
if let InstanceType::Object = inst.instance_type {
|
||||
let mut light_instances = self.instances.clone();
|
||||
let light_accel = LightArray::new(&mut light_instances[..], |inst| {
|
||||
match inst.instance_type {
|
||||
InstanceType::Object => {
|
||||
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 {
|
||||
instances: self.instances,
|
||||
light_instances: light_instances,
|
||||
xforms: self.xforms,
|
||||
objects: self.objects,
|
||||
assemblies: self.assemblies,
|
||||
|
|
50
src/light_accel/mod.rs
Normal file
50
src/light_accel/mod.rs
Normal 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))
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ mod triangle;
|
|||
mod surface;
|
||||
mod light;
|
||||
mod bvh;
|
||||
mod light_accel;
|
||||
mod scene;
|
||||
mod assembly;
|
||||
mod halton;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::result::Result;
|
||||
use std::cmp::Eq;
|
||||
use std::iter::Iterator;
|
||||
use std::slice;
|
||||
|
||||
|
|
|
@ -2,23 +2,19 @@
|
|||
|
||||
use std::path::Path;
|
||||
use std::cmp::min;
|
||||
use std::iter::Iterator;
|
||||
use std::sync::RwLock;
|
||||
use scoped_threadpool::Pool;
|
||||
use crossbeam::sync::MsQueue;
|
||||
|
||||
use algorithm::partition_pair;
|
||||
use lerp::lerp_slice;
|
||||
use ray::Ray;
|
||||
use assembly::Object;
|
||||
use tracer::Tracer;
|
||||
use halton;
|
||||
use math::{Matrix4x4, fast_logit};
|
||||
use math::fast_logit;
|
||||
use image::Image;
|
||||
use surface;
|
||||
use scene::Scene;
|
||||
use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength};
|
||||
use shading::surface_closure::{SurfaceClosure, LambertClosure};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
|
@ -239,31 +235,10 @@ impl LightPath {
|
|||
self.interaction = *isect; // Store interaction for use in next phase
|
||||
|
||||
// Prepare light ray
|
||||
if scene.root.light_accel.len() > 0 {
|
||||
// Get the light and the mapping to its local space
|
||||
let (light, space) = {
|
||||
let l1 = &scene.root.objects[scene.root.light_accel[0].data_index];
|
||||
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)
|
||||
};
|
||||
|
||||
let light_n = self.next_lds_samp();
|
||||
let light_uvw = (self.next_lds_samp(), self.next_lds_samp(), self.next_lds_samp());
|
||||
if let Some((light_color, shadow_vec, light_pdf)) = scene.root
|
||||
.sample_lights(light_n, light_uvw, self.wavelength, self.time, isect) {
|
||||
// Calculate and store the light that will be contributed
|
||||
// to the film plane if the light is not in shadow.
|
||||
self.pending_color_addition = {
|
||||
|
|
Loading…
Reference in New Issue
Block a user