Multiple light sources are now handled.
This commit is contained in:
parent
9c8797ffd8
commit
5df583c2d0
|
@ -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
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 surface;
|
||||||
mod light;
|
mod light;
|
||||||
mod bvh;
|
mod bvh;
|
||||||
|
mod light_accel;
|
||||||
mod scene;
|
mod scene;
|
||||||
mod assembly;
|
mod assembly;
|
||||||
mod halton;
|
mod halton;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user