Compare commits
No commits in common. "6ccd4e306daae68a6bd85d37f6694ffd7645d10d" and "608fe8bda196a84fe22cae583d3a0b81fbfacf88" have entirely different histories.
6ccd4e306d
...
608fe8bda1
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
RUSTFLAGS="-C target-cpu=native" cargo build --release
|
|
|
@ -52,6 +52,7 @@ use crate::{
|
||||||
accel::BVH4Node,
|
accel::BVH4Node,
|
||||||
bbox::BBox,
|
bbox::BBox,
|
||||||
parse::{parse_scene, DataTree},
|
parse::{parse_scene, DataTree},
|
||||||
|
renderer::LightPath,
|
||||||
surface::SurfaceIntersection,
|
surface::SurfaceIntersection,
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
};
|
};
|
||||||
|
@ -163,6 +164,7 @@ fn main() {
|
||||||
"SurfaceIntersection size: {} bytes",
|
"SurfaceIntersection size: {} bytes",
|
||||||
mem::size_of::<SurfaceIntersection>()
|
mem::size_of::<SurfaceIntersection>()
|
||||||
);
|
);
|
||||||
|
println!("LightPath size: {} bytes", mem::size_of::<LightPath>());
|
||||||
println!("BBox size: {} bytes", mem::size_of::<BBox>());
|
println!("BBox size: {} bytes", mem::size_of::<BBox>());
|
||||||
// println!("BVHNode size: {} bytes", mem::size_of::<BVHNode>());
|
// println!("BVHNode size: {} bytes", mem::size_of::<BVHNode>());
|
||||||
println!("BVH4Node size: {} bytes", mem::size_of::<BVH4Node>());
|
println!("BVH4Node size: {} bytes", mem::size_of::<BVH4Node>());
|
||||||
|
|
636
src/renderer.rs
636
src/renderer.rs
|
@ -20,6 +20,7 @@ use crate::{
|
||||||
scene::{Scene, SceneLightSample},
|
scene::{Scene, SceneLightSample},
|
||||||
scramble::owen4,
|
scramble::owen4,
|
||||||
space_fill::{hilbert, morton},
|
space_fill::{hilbert, morton},
|
||||||
|
surface,
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
tracer::Tracer,
|
tracer::Tracer,
|
||||||
};
|
};
|
||||||
|
@ -242,7 +243,7 @@ impl<'a> Renderer<'a> {
|
||||||
let (d1, d2, d3, d4) = get_sample_4d(si, 0, self.seed);
|
let (d1, d2, d3, d4) = get_sample_4d(si, 0, self.seed);
|
||||||
let (d5, _, _, _) = get_sample_4d(si, 1, self.seed);
|
let (d5, _, _, _) = get_sample_4d(si, 1, self.seed);
|
||||||
|
|
||||||
// Calculate the values we need to generate a camera ray.
|
// Calculate image plane x and y coordinates
|
||||||
let (img_x, img_y) = {
|
let (img_x, img_y) = {
|
||||||
let filter_x = probit(d4, 2.0 / 6.0) + 0.5;
|
let filter_x = probit(d4, 2.0 / 6.0) + 0.5;
|
||||||
let filter_y = probit(d5, 2.0 / 6.0) + 0.5;
|
let filter_y = probit(d5, 2.0 / 6.0) + 0.5;
|
||||||
|
@ -250,19 +251,31 @@ impl<'a> Renderer<'a> {
|
||||||
let samp_y = (filter_y + y as f32) * cmpy;
|
let samp_y = (filter_y + y as f32) * cmpy;
|
||||||
((samp_x - 0.5) * x_extent, (0.5 - samp_y) * y_extent)
|
((samp_x - 0.5) * x_extent, (0.5 - samp_y) * y_extent)
|
||||||
};
|
};
|
||||||
let wavelength = map_0_1_to_wavelength(d0);
|
|
||||||
let time = d1;
|
|
||||||
let lens_uv = (d2, d3);
|
|
||||||
|
|
||||||
// Trace light path starting from a camera ray.
|
// Create the light path and initial ray for this sample.
|
||||||
let ray = self
|
let (mut path, mut ray) = LightPath::new(
|
||||||
.scene
|
&self.scene,
|
||||||
.camera
|
self.seed,
|
||||||
.generate_ray(img_x, img_y, time, wavelength, lens_uv.0, lens_uv.1);
|
(x, y),
|
||||||
let path_col =
|
(img_x, img_y),
|
||||||
trace_camera_light_path(&mut tracer, &self.scene, ray, si, self.seed);
|
(d2, d3),
|
||||||
|
d1,
|
||||||
|
map_0_1_to_wavelength(d0),
|
||||||
|
si as u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Trace light path.
|
||||||
|
let mut isect;
|
||||||
|
loop {
|
||||||
|
isect = surface::SurfaceIntersection::Miss;
|
||||||
|
tracer.trace(&mut ray, &mut isect);
|
||||||
|
if !path.next(&self.scene, &isect, &mut ray) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Accummulate light path color to pixel.
|
// Accummulate light path color to pixel.
|
||||||
|
let path_col = SpectralSample::from_parts(path.color, path.wavelength);
|
||||||
let mut col = img_bucket.get(x, y);
|
let mut col = img_bucket.get(x, y);
|
||||||
col += XYZ::from_spectral_sample(&path_col) / self.spp as f32;
|
col += XYZ::from_spectral_sample(&path_col) / self.spp as f32;
|
||||||
img_bucket.set(x, y, col);
|
img_bucket.set(x, y, col);
|
||||||
|
@ -321,77 +334,153 @@ impl<'a> Renderer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_camera_light_path(
|
#[derive(Debug)]
|
||||||
tracer: &mut Tracer,
|
enum LightPathEvent {
|
||||||
|
CameraRay,
|
||||||
|
BounceRay,
|
||||||
|
ShadowRay,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LightPath {
|
||||||
|
event: LightPathEvent,
|
||||||
|
bounce_count: u32,
|
||||||
|
|
||||||
|
sampling_seed: u32,
|
||||||
|
pixel_co: (u32, u32),
|
||||||
|
sample_number: u32, // Which sample in the LDS sequence this is.
|
||||||
|
dim_offset: u32,
|
||||||
|
time: f32,
|
||||||
|
wavelength: f32,
|
||||||
|
|
||||||
|
next_bounce_ray: Option<Ray>,
|
||||||
|
next_attenuation_fac: Float4,
|
||||||
|
|
||||||
|
closure_sample_pdf: f32,
|
||||||
|
light_attenuation: Float4,
|
||||||
|
pending_color_addition: Float4,
|
||||||
|
color: Float4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
impl LightPath {
|
||||||
|
fn new(
|
||||||
scene: &Scene,
|
scene: &Scene,
|
||||||
camera_ray: Ray,
|
sampling_seed: u32,
|
||||||
sample_index: u32,
|
pixel_co: (u32, u32),
|
||||||
seed: u32,
|
image_plane_co: (f32, f32),
|
||||||
) -> SpectralSample {
|
lens_uv: (f32, f32),
|
||||||
use crate::shading::surface_closure::SurfaceClosure;
|
time: f32,
|
||||||
use crate::surface::SurfaceIntersection;
|
wavelength: f32,
|
||||||
|
sample_number: u32,
|
||||||
|
) -> (LightPath, Ray) {
|
||||||
|
(
|
||||||
|
LightPath {
|
||||||
|
event: LightPathEvent::CameraRay,
|
||||||
|
bounce_count: 0,
|
||||||
|
|
||||||
const BOUNCE_COUNT: usize = 3;
|
sampling_seed: sampling_seed ^ 0x40d4682b,
|
||||||
|
pixel_co: pixel_co,
|
||||||
|
sample_number: sample_number,
|
||||||
|
dim_offset: 0,
|
||||||
|
time: time,
|
||||||
|
wavelength: wavelength,
|
||||||
|
|
||||||
let mut ray = camera_ray;
|
next_bounce_ray: None,
|
||||||
let mut ray_pdf = 1.0; // PDF from generating the ray.
|
next_attenuation_fac: Float4::splat(1.0),
|
||||||
let mut acc_color = Float4::splat(0.0); // Accumulated color.
|
|
||||||
let mut attenuation = Float4::splat(1.0); // Color attenuation along the path so far.
|
|
||||||
let mut sampling_seed = seed + 1;
|
|
||||||
|
|
||||||
for _ in 0..BOUNCE_COUNT {
|
closure_sample_pdf: 1.0,
|
||||||
let isect = tracer.trace(&mut ray);
|
light_attenuation: Float4::splat(1.0),
|
||||||
if let SurfaceIntersection::Hit {
|
pending_color_addition: Float4::splat(0.0),
|
||||||
intersection_data: idata,
|
color: Float4::splat(0.0),
|
||||||
closure,
|
},
|
||||||
} = &isect
|
scene.camera.generate_ray(
|
||||||
|
image_plane_co.0,
|
||||||
|
image_plane_co.1,
|
||||||
|
time,
|
||||||
|
wavelength,
|
||||||
|
lens_uv.0,
|
||||||
|
lens_uv.1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_lds_sequence(&mut self) {
|
||||||
|
self.dim_offset = 0;
|
||||||
|
self.sampling_seed += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_lds_samp(&mut self) -> (f32, f32, f32, f32) {
|
||||||
|
let dimension = self.dim_offset;
|
||||||
|
self.dim_offset += 1;
|
||||||
|
get_sample_4d(self.sample_number, dimension, self.sampling_seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self, scene: &Scene, isect: &surface::SurfaceIntersection, ray: &mut Ray) -> bool {
|
||||||
|
match self.event {
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Result of Camera or bounce ray, prepare next bounce and light rays
|
||||||
|
LightPathEvent::CameraRay | LightPathEvent::BounceRay => {
|
||||||
|
if let surface::SurfaceIntersection::Hit {
|
||||||
|
intersection_data: ref idata,
|
||||||
|
ref closure,
|
||||||
|
} = *isect
|
||||||
{
|
{
|
||||||
// Hit something! Do the stuff
|
// Hit something! Do the stuff
|
||||||
|
|
||||||
// If it's an emission closure, handle specially:
|
// If it's an emission closure, handle specially:
|
||||||
// - Collect light from the emission.
|
// - Collect light from the emission.
|
||||||
// - Terminate the path.
|
// - Terminate the path.
|
||||||
|
use crate::shading::surface_closure::SurfaceClosure;
|
||||||
if let SurfaceClosure::Emit(color) = *closure {
|
if let SurfaceClosure::Emit(color) = *closure {
|
||||||
let mis_pdf = power_heuristic(ray_pdf, idata.sample_pdf);
|
let color = color.to_spectral_sample(self.wavelength).e;
|
||||||
acc_color += color.to_spectral_sample(ray.wavelength).e * attenuation / mis_pdf;
|
if let LightPathEvent::CameraRay = self.event {
|
||||||
|
self.color += color;
|
||||||
|
} else {
|
||||||
|
let mis_pdf =
|
||||||
|
power_heuristic(self.closure_sample_pdf, idata.sample_pdf);
|
||||||
|
self.color += color * self.light_attenuation / mis_pdf;
|
||||||
|
};
|
||||||
|
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roll the previous closure pdf into the attenauation
|
// Roll the previous closure pdf into the attenauation
|
||||||
attenuation /= ray_pdf;
|
self.light_attenuation /= self.closure_sample_pdf;
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// Sample light sources.
|
|
||||||
|
|
||||||
sampling_seed = sampling_seed.wrapping_add(1);
|
|
||||||
let (light_n, d2, d3, d4) = get_sample_4d(sample_index, 0, sampling_seed);
|
|
||||||
|
|
||||||
|
// Prepare light ray
|
||||||
|
self.next_lds_sequence();
|
||||||
|
let (light_n, d2, d3, d4) = self.next_lds_samp();
|
||||||
let light_uvw = (d2, d3, d4);
|
let light_uvw = (d2, d3, d4);
|
||||||
let light_info = scene.sample_lights(
|
let light_info = scene.sample_lights(
|
||||||
light_n,
|
light_n,
|
||||||
light_uvw,
|
light_uvw,
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
ray.time,
|
self.time,
|
||||||
&XformFull::identity(),
|
&XformFull::identity(),
|
||||||
&isect,
|
isect,
|
||||||
);
|
);
|
||||||
if !light_info.is_none() && light_info.pdf() > 0.0 && light_info.selection_pdf() > 0.0 {
|
let found_light = if light_info.is_none()
|
||||||
|
|| light_info.pdf() <= 0.0
|
||||||
|
|| light_info.selection_pdf() <= 0.0
|
||||||
|
{
|
||||||
|
false
|
||||||
|
} else {
|
||||||
let light_pdf = light_info.pdf();
|
let light_pdf = light_info.pdf();
|
||||||
let light_sel_pdf = light_info.selection_pdf();
|
let light_sel_pdf = light_info.selection_pdf();
|
||||||
|
|
||||||
// Calculate the shadow ray and surface closure stuff.
|
// Calculate the shadow ray and surface closure stuff
|
||||||
let (light_attenuation, closure_pdf, mut shadow_ray) = match light_info {
|
let (attenuation, closure_pdf, shadow_ray) = match light_info {
|
||||||
SceneLightSample::None => unreachable!(),
|
SceneLightSample::None => unreachable!(),
|
||||||
|
|
||||||
// Distant light
|
// Distant light
|
||||||
SceneLightSample::Distant { direction, .. } => {
|
SceneLightSample::Distant { direction, .. } => {
|
||||||
let (light_attenuation, closure_pdf) = closure.evaluate(
|
let (attenuation, closure_pdf) = closure.evaluate(
|
||||||
ray.dir,
|
ray.dir,
|
||||||
direction,
|
direction,
|
||||||
idata.nor,
|
idata.nor,
|
||||||
idata.nor_g,
|
idata.nor_g,
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
);
|
);
|
||||||
let shadow_ray = {
|
let shadow_ray = {
|
||||||
// Calculate the shadow ray for testing if the light is
|
// Calculate the shadow ray for testing if the light is
|
||||||
|
@ -405,20 +494,25 @@ fn trace_camera_light_path(
|
||||||
Ray::new(
|
Ray::new(
|
||||||
offset_pos,
|
offset_pos,
|
||||||
direction,
|
direction,
|
||||||
ray.time,
|
self.time,
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
std::f32::INFINITY,
|
std::f32::INFINITY,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
(light_attenuation, closure_pdf, shadow_ray)
|
(attenuation, closure_pdf, shadow_ray)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Surface light
|
// Surface light
|
||||||
SceneLightSample::Surface { sample_geo, .. } => {
|
SceneLightSample::Surface { sample_geo, .. } => {
|
||||||
let dir = sample_geo.0 - idata.pos;
|
let dir = sample_geo.0 - idata.pos;
|
||||||
let (light_attenuation, closure_pdf) =
|
let (attenuation, closure_pdf) = closure.evaluate(
|
||||||
closure.evaluate(ray.dir, dir, idata.nor, idata.nor_g, ray.wavelength);
|
ray.dir,
|
||||||
|
dir,
|
||||||
|
idata.nor,
|
||||||
|
idata.nor_g,
|
||||||
|
self.wavelength,
|
||||||
|
);
|
||||||
let shadow_ray = {
|
let shadow_ray = {
|
||||||
// Calculate the shadow ray for testing if the light is
|
// Calculate the shadow ray for testing if the light is
|
||||||
// in shadow or not.
|
// in shadow or not.
|
||||||
|
@ -437,43 +531,48 @@ fn trace_camera_light_path(
|
||||||
Ray::new(
|
Ray::new(
|
||||||
offset_pos,
|
offset_pos,
|
||||||
offset_end - offset_pos,
|
offset_end - offset_pos,
|
||||||
ray.time,
|
self.time,
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
1.0,
|
1.0,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
(light_attenuation, closure_pdf, shadow_ray)
|
(attenuation, closure_pdf, shadow_ray)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If there's any possible contribution, shoot a shadow
|
// If there's any possible contribution, set up for a
|
||||||
// ray to see if we can reach it.
|
// light ray.
|
||||||
if light_attenuation.e.max_element() > 0.0 {
|
if attenuation.e.max_element() <= 0.0 {
|
||||||
if let SurfaceIntersection::Occlude = tracer.trace(&mut shadow_ray) {
|
false
|
||||||
|
} else {
|
||||||
// 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.
|
||||||
let light_mis_pdf = power_heuristic(light_pdf, closure_pdf);
|
let light_mis_pdf = power_heuristic(light_pdf, closure_pdf);
|
||||||
acc_color += light_info.color().e * light_attenuation.e * attenuation
|
self.pending_color_addition =
|
||||||
|
light_info.color().e * attenuation.e * self.light_attenuation
|
||||||
/ (light_mis_pdf * light_sel_pdf);
|
/ (light_mis_pdf * light_sel_pdf);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
*ray = shadow_ray;
|
||||||
// Prepare next bounce ray.
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prepare bounce ray
|
||||||
|
let do_bounce = if self.bounce_count < 2 {
|
||||||
|
self.bounce_count += 1;
|
||||||
|
|
||||||
// Sample closure
|
// Sample closure
|
||||||
let (dir, filter, pdf) = {
|
let (dir, filter, pdf) = {
|
||||||
sampling_seed = sampling_seed.wrapping_add(1);
|
self.next_lds_sequence();
|
||||||
let (u, v, _, _) = get_sample_4d(sample_index, 0, sampling_seed);
|
let (u, v, _, _) = self.next_lds_samp();
|
||||||
|
|
||||||
closure.sample(
|
closure.sample(
|
||||||
idata.incoming,
|
idata.incoming,
|
||||||
idata.nor,
|
idata.nor,
|
||||||
idata.nor_g,
|
idata.nor_g,
|
||||||
(u, v),
|
(u, v),
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,351 +580,82 @@ fn trace_camera_light_path(
|
||||||
if (pdf > 0.0) && (filter.e.max_element() > 0.0) {
|
if (pdf > 0.0) && (filter.e.max_element() > 0.0) {
|
||||||
// Account for the additional light attenuation from
|
// Account for the additional light attenuation from
|
||||||
// this bounce
|
// this bounce
|
||||||
attenuation *= filter.e;
|
self.next_attenuation_fac = filter.e;
|
||||||
ray_pdf = pdf;
|
self.closure_sample_pdf = pdf;
|
||||||
|
|
||||||
// Calculate the ray for this bounce
|
// Calculate the ray for this bounce
|
||||||
let offset_pos =
|
let offset_pos = robust_ray_origin(
|
||||||
robust_ray_origin(idata.pos, idata.pos_err, idata.nor_g.normalized(), dir);
|
idata.pos,
|
||||||
ray = Ray::new(
|
idata.pos_err,
|
||||||
|
idata.nor_g.normalized(),
|
||||||
|
dir,
|
||||||
|
);
|
||||||
|
self.next_bounce_ray = Some(Ray::new(
|
||||||
offset_pos,
|
offset_pos,
|
||||||
dir,
|
dir,
|
||||||
ray.time,
|
self.time,
|
||||||
ray.wavelength,
|
self.wavelength,
|
||||||
std::f32::INFINITY,
|
std::f32::INFINITY,
|
||||||
false,
|
false,
|
||||||
);
|
));
|
||||||
|
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
break;
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.next_bounce_ray = None;
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Book keeping for next event
|
||||||
|
if found_light {
|
||||||
|
self.event = LightPathEvent::ShadowRay;
|
||||||
|
return true;
|
||||||
|
} else if do_bounce {
|
||||||
|
*ray = self.next_bounce_ray.unwrap();
|
||||||
|
self.event = LightPathEvent::BounceRay;
|
||||||
|
self.light_attenuation *= self.next_attenuation_fac;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Didn't hit anything, so background color
|
||||||
|
self.color += scene
|
||||||
|
.world
|
||||||
|
.background_color
|
||||||
|
.to_spectral_sample(self.wavelength)
|
||||||
|
.e
|
||||||
|
* self.light_attenuation
|
||||||
|
/ self.closure_sample_pdf;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectralSample::from_parts(acc_color, ray.wavelength)
|
//--------------------------------------------------------------------
|
||||||
|
// Result of shadow ray from sampling a light
|
||||||
|
LightPathEvent::ShadowRay => {
|
||||||
|
// If the light was not in shadow, add it's light to the film
|
||||||
|
// plane.
|
||||||
|
if let surface::SurfaceIntersection::Miss = *isect {
|
||||||
|
self.color += self.pending_color_addition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up for the next bounce, if any
|
||||||
|
if let Some(ref nbr) = self.next_bounce_ray {
|
||||||
|
*ray = *nbr;
|
||||||
|
self.light_attenuation *= self.next_attenuation_fac;
|
||||||
|
self.event = LightPathEvent::BounceRay;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// enum LightPathEvent {
|
|
||||||
// CameraRay,
|
|
||||||
// BounceRay,
|
|
||||||
// ShadowRay,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// pub struct LightPath {
|
|
||||||
// event: LightPathEvent,
|
|
||||||
// bounce_count: u32,
|
|
||||||
|
|
||||||
// sampling_seed: u32,
|
|
||||||
// pixel_co: (u32, u32),
|
|
||||||
// sample_number: u32, // Which sample in the LDS sequence this is.
|
|
||||||
// dim_offset: u32,
|
|
||||||
// time: f32,
|
|
||||||
// wavelength: f32,
|
|
||||||
|
|
||||||
// next_bounce_ray: Option<Ray>,
|
|
||||||
// next_attenuation_fac: Float4,
|
|
||||||
|
|
||||||
// closure_sample_pdf: f32,
|
|
||||||
// light_attenuation: Float4,
|
|
||||||
// pending_color_addition: Float4,
|
|
||||||
// color: Float4,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[allow(clippy::new_ret_no_self)]
|
|
||||||
// impl LightPath {
|
|
||||||
// fn new(
|
|
||||||
// scene: &Scene,
|
|
||||||
// sampling_seed: u32,
|
|
||||||
// pixel_co: (u32, u32),
|
|
||||||
// image_plane_co: (f32, f32),
|
|
||||||
// lens_uv: (f32, f32),
|
|
||||||
// time: f32,
|
|
||||||
// wavelength: f32,
|
|
||||||
// sample_number: u32,
|
|
||||||
// ) -> (LightPath, Ray) {
|
|
||||||
// (
|
|
||||||
// LightPath {
|
|
||||||
// event: LightPathEvent::CameraRay,
|
|
||||||
// bounce_count: 0,
|
|
||||||
|
|
||||||
// sampling_seed: sampling_seed ^ 0x40d4682b,
|
|
||||||
// pixel_co: pixel_co,
|
|
||||||
// sample_number: sample_number,
|
|
||||||
// dim_offset: 0,
|
|
||||||
// time: time,
|
|
||||||
// wavelength: wavelength,
|
|
||||||
|
|
||||||
// next_bounce_ray: None,
|
|
||||||
// next_attenuation_fac: Float4::splat(1.0),
|
|
||||||
|
|
||||||
// closure_sample_pdf: 1.0,
|
|
||||||
// light_attenuation: Float4::splat(1.0),
|
|
||||||
// pending_color_addition: Float4::splat(0.0),
|
|
||||||
// color: Float4::splat(0.0),
|
|
||||||
// },
|
|
||||||
// scene.camera.generate_ray(
|
|
||||||
// image_plane_co.0,
|
|
||||||
// image_plane_co.1,
|
|
||||||
// time,
|
|
||||||
// wavelength,
|
|
||||||
// lens_uv.0,
|
|
||||||
// lens_uv.1,
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn next_lds_sequence(&mut self) {
|
|
||||||
// self.dim_offset = 0;
|
|
||||||
// self.sampling_seed += 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn next_lds_samp(&mut self) -> (f32, f32, f32, f32) {
|
|
||||||
// let dimension = self.dim_offset;
|
|
||||||
// self.dim_offset += 1;
|
|
||||||
// get_sample_4d(self.sample_number, dimension, self.sampling_seed)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn next(&mut self, scene: &Scene, isect: &surface::SurfaceIntersection, ray: &mut Ray) -> bool {
|
|
||||||
// match self.event {
|
|
||||||
// //--------------------------------------------------------------------
|
|
||||||
// // Result of Camera or bounce ray, prepare next bounce and light rays
|
|
||||||
// LightPathEvent::CameraRay | LightPathEvent::BounceRay => {
|
|
||||||
// if let surface::SurfaceIntersection::Hit {
|
|
||||||
// intersection_data: ref idata,
|
|
||||||
// ref closure,
|
|
||||||
// } = *isect
|
|
||||||
// {
|
|
||||||
// // Hit something! Do the stuff
|
|
||||||
|
|
||||||
// // If it's an emission closure, handle specially:
|
|
||||||
// // - Collect light from the emission.
|
|
||||||
// // - Terminate the path.
|
|
||||||
// use crate::shading::surface_closure::SurfaceClosure;
|
|
||||||
// if let SurfaceClosure::Emit(color) = *closure {
|
|
||||||
// let color = color.to_spectral_sample(self.wavelength).e;
|
|
||||||
// if let LightPathEvent::CameraRay = self.event {
|
|
||||||
// self.color += color;
|
|
||||||
// } else {
|
|
||||||
// let mis_pdf =
|
|
||||||
// power_heuristic(self.closure_sample_pdf, idata.sample_pdf);
|
|
||||||
// self.color += color * self.light_attenuation / mis_pdf;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Roll the previous closure pdf into the attenauation
|
|
||||||
// self.light_attenuation /= self.closure_sample_pdf;
|
|
||||||
|
|
||||||
// // Prepare light ray
|
|
||||||
// self.next_lds_sequence();
|
|
||||||
// let (light_n, d2, d3, d4) = self.next_lds_samp();
|
|
||||||
// let light_uvw = (d2, d3, d4);
|
|
||||||
// let light_info = scene.sample_lights(
|
|
||||||
// light_n,
|
|
||||||
// light_uvw,
|
|
||||||
// self.wavelength,
|
|
||||||
// self.time,
|
|
||||||
// &XformFull::identity(),
|
|
||||||
// isect,
|
|
||||||
// );
|
|
||||||
// let found_light = if light_info.is_none()
|
|
||||||
// || light_info.pdf() <= 0.0
|
|
||||||
// || light_info.selection_pdf() <= 0.0
|
|
||||||
// {
|
|
||||||
// false
|
|
||||||
// } else {
|
|
||||||
// let light_pdf = light_info.pdf();
|
|
||||||
// let light_sel_pdf = light_info.selection_pdf();
|
|
||||||
|
|
||||||
// // Calculate the shadow ray and surface closure stuff
|
|
||||||
// let (attenuation, closure_pdf, shadow_ray) = match light_info {
|
|
||||||
// SceneLightSample::None => unreachable!(),
|
|
||||||
|
|
||||||
// // Distant light
|
|
||||||
// SceneLightSample::Distant { direction, .. } => {
|
|
||||||
// let (attenuation, closure_pdf) = closure.evaluate(
|
|
||||||
// ray.dir,
|
|
||||||
// direction,
|
|
||||||
// idata.nor,
|
|
||||||
// idata.nor_g,
|
|
||||||
// self.wavelength,
|
|
||||||
// );
|
|
||||||
// let shadow_ray = {
|
|
||||||
// // Calculate the shadow ray for testing if the light is
|
|
||||||
// // in shadow or not.
|
|
||||||
// let offset_pos = robust_ray_origin(
|
|
||||||
// idata.pos,
|
|
||||||
// idata.pos_err,
|
|
||||||
// idata.nor_g.normalized(),
|
|
||||||
// direction,
|
|
||||||
// );
|
|
||||||
// Ray::new(
|
|
||||||
// offset_pos,
|
|
||||||
// direction,
|
|
||||||
// self.time,
|
|
||||||
// self.wavelength,
|
|
||||||
// std::f32::INFINITY,
|
|
||||||
// true,
|
|
||||||
// )
|
|
||||||
// };
|
|
||||||
// (attenuation, closure_pdf, shadow_ray)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Surface light
|
|
||||||
// SceneLightSample::Surface { sample_geo, .. } => {
|
|
||||||
// let dir = sample_geo.0 - idata.pos;
|
|
||||||
// let (attenuation, closure_pdf) = closure.evaluate(
|
|
||||||
// ray.dir,
|
|
||||||
// dir,
|
|
||||||
// idata.nor,
|
|
||||||
// idata.nor_g,
|
|
||||||
// self.wavelength,
|
|
||||||
// );
|
|
||||||
// let shadow_ray = {
|
|
||||||
// // Calculate the shadow ray for testing if the light is
|
|
||||||
// // in shadow or not.
|
|
||||||
// let offset_pos = robust_ray_origin(
|
|
||||||
// idata.pos,
|
|
||||||
// idata.pos_err,
|
|
||||||
// idata.nor_g.normalized(),
|
|
||||||
// dir,
|
|
||||||
// );
|
|
||||||
// let offset_end = robust_ray_origin(
|
|
||||||
// sample_geo.0,
|
|
||||||
// sample_geo.2,
|
|
||||||
// sample_geo.1.normalized(),
|
|
||||||
// -dir,
|
|
||||||
// );
|
|
||||||
// Ray::new(
|
|
||||||
// offset_pos,
|
|
||||||
// offset_end - offset_pos,
|
|
||||||
// self.time,
|
|
||||||
// self.wavelength,
|
|
||||||
// 1.0,
|
|
||||||
// true,
|
|
||||||
// )
|
|
||||||
// };
|
|
||||||
// (attenuation, closure_pdf, shadow_ray)
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // If there's any possible contribution, set up for a
|
|
||||||
// // light ray.
|
|
||||||
// if attenuation.e.max_element() <= 0.0 {
|
|
||||||
// false
|
|
||||||
// } else {
|
|
||||||
// // Calculate and store the light that will be contributed
|
|
||||||
// // to the film plane if the light is not in shadow.
|
|
||||||
// let light_mis_pdf = power_heuristic(light_pdf, closure_pdf);
|
|
||||||
// self.pending_color_addition =
|
|
||||||
// light_info.color().e * attenuation.e * self.light_attenuation
|
|
||||||
// / (light_mis_pdf * light_sel_pdf);
|
|
||||||
|
|
||||||
// *ray = shadow_ray;
|
|
||||||
|
|
||||||
// true
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Prepare bounce ray
|
|
||||||
// let do_bounce = if self.bounce_count < 2 {
|
|
||||||
// self.bounce_count += 1;
|
|
||||||
|
|
||||||
// // Sample closure
|
|
||||||
// let (dir, filter, pdf) = {
|
|
||||||
// self.next_lds_sequence();
|
|
||||||
// let (u, v, _, _) = self.next_lds_samp();
|
|
||||||
// closure.sample(
|
|
||||||
// idata.incoming,
|
|
||||||
// idata.nor,
|
|
||||||
// idata.nor_g,
|
|
||||||
// (u, v),
|
|
||||||
// self.wavelength,
|
|
||||||
// )
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Check if pdf is zero, to avoid NaN's.
|
|
||||||
// if (pdf > 0.0) && (filter.e.max_element() > 0.0) {
|
|
||||||
// // Account for the additional light attenuation from
|
|
||||||
// // this bounce
|
|
||||||
// self.next_attenuation_fac = filter.e;
|
|
||||||
// self.closure_sample_pdf = pdf;
|
|
||||||
|
|
||||||
// // Calculate the ray for this bounce
|
|
||||||
// let offset_pos = robust_ray_origin(
|
|
||||||
// idata.pos,
|
|
||||||
// idata.pos_err,
|
|
||||||
// idata.nor_g.normalized(),
|
|
||||||
// dir,
|
|
||||||
// );
|
|
||||||
// self.next_bounce_ray = Some(Ray::new(
|
|
||||||
// offset_pos,
|
|
||||||
// dir,
|
|
||||||
// self.time,
|
|
||||||
// self.wavelength,
|
|
||||||
// std::f32::INFINITY,
|
|
||||||
// false,
|
|
||||||
// ));
|
|
||||||
|
|
||||||
// true
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// self.next_bounce_ray = None;
|
|
||||||
// false
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Book keeping for next event
|
|
||||||
// if found_light {
|
|
||||||
// self.event = LightPathEvent::ShadowRay;
|
|
||||||
// return true;
|
|
||||||
// } else if do_bounce {
|
|
||||||
// *ray = self.next_bounce_ray.unwrap();
|
|
||||||
// self.event = LightPathEvent::BounceRay;
|
|
||||||
// self.light_attenuation *= self.next_attenuation_fac;
|
|
||||||
// return true;
|
|
||||||
// } else {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // Didn't hit anything, so background color
|
|
||||||
// self.color += scene
|
|
||||||
// .world
|
|
||||||
// .background_color
|
|
||||||
// .to_spectral_sample(self.wavelength)
|
|
||||||
// .e
|
|
||||||
// * self.light_attenuation
|
|
||||||
// / self.closure_sample_pdf;
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// //--------------------------------------------------------------------
|
|
||||||
// // Result of shadow ray from sampling a light
|
|
||||||
// LightPathEvent::ShadowRay => {
|
|
||||||
// // If the light was not in shadow, add it's light to the film
|
|
||||||
// // plane.
|
|
||||||
// if let surface::SurfaceIntersection::Miss = *isect {
|
|
||||||
// self.color += self.pending_color_addition;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Set up for the next bounce, if any
|
|
||||||
// if let Some(ref nbr) = self.next_bounce_ray {
|
|
||||||
// *ray = *nbr;
|
|
||||||
// self.light_attenuation *= self.next_attenuation_fac;
|
|
||||||
// self.event = LightPathEvent::BounceRay;
|
|
||||||
// return true;
|
|
||||||
// } else {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// Gets a sample, using LDS samples for lower dimensions,
|
/// Gets a sample, using LDS samples for lower dimensions,
|
||||||
/// and switching to random samples at higher dimensions where
|
/// and switching to random samples at higher dimensions where
|
||||||
/// LDS samples aren't available.
|
/// LDS samples aren't available.
|
||||||
|
|
|
@ -25,16 +25,13 @@ impl<'a> Tracer<'a> {
|
||||||
self.ray_trace_count
|
self.ray_trace_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace(&mut self, ray: &mut Ray) -> SurfaceIntersection {
|
pub fn trace(&mut self, ray: &mut Ray, isect: &mut SurfaceIntersection) {
|
||||||
self.ray_trace_count += 1;
|
self.ray_trace_count += 1;
|
||||||
|
|
||||||
let local_ray = ray.to_local();
|
let local_ray = ray.to_local();
|
||||||
let space = XformFull::identity();
|
let space = XformFull::identity();
|
||||||
let mut isect = SurfaceIntersection::Miss;
|
|
||||||
|
|
||||||
self.trace_assembly(self.root, ray, &local_ray, &space, &mut isect);
|
self.trace_assembly(self.root, ray, &local_ray, &space, isect);
|
||||||
|
|
||||||
isect
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_assembly(
|
fn trace_assembly(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user