Refactored some parts of Renderer to take up less memory and be faster.
Specifically, LightPath is now significantly smaller, and resultingly faster to process. Also finally fixed the bug where without light sources the light from the sky wouldn't affect surfaces.
This commit is contained in:
parent
a3a19e53ef
commit
96db00b10a
215
src/renderer.rs
215
src/renderer.rs
|
@ -293,15 +293,27 @@ impl<'a> Renderer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum LightPathEvent {
|
||||||
|
CameraRay,
|
||||||
|
BounceRay,
|
||||||
|
ShadowRay,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LightPath {
|
pub struct LightPath {
|
||||||
|
event: LightPathEvent,
|
||||||
|
bounce_count: u32,
|
||||||
|
|
||||||
pixel_co: (u32, u32),
|
pixel_co: (u32, u32),
|
||||||
lds_offset: u32,
|
lds_offset: u32,
|
||||||
dim_offset: Cell<u32>,
|
dim_offset: Cell<u32>,
|
||||||
round: u32,
|
|
||||||
time: f32,
|
time: f32,
|
||||||
wavelength: f32,
|
wavelength: f32,
|
||||||
interaction: surface::SurfaceIntersection,
|
|
||||||
|
next_bounce_ray: Option<Ray>,
|
||||||
|
next_attentuation_fac: Float4,
|
||||||
|
|
||||||
light_attenuation: Float4,
|
light_attenuation: Float4,
|
||||||
pending_color_addition: Float4,
|
pending_color_addition: Float4,
|
||||||
color: Float4,
|
color: Float4,
|
||||||
|
@ -317,13 +329,18 @@ impl LightPath {
|
||||||
lds_offset: u32)
|
lds_offset: u32)
|
||||||
-> (LightPath, Ray) {
|
-> (LightPath, Ray) {
|
||||||
(LightPath {
|
(LightPath {
|
||||||
|
event: LightPathEvent::CameraRay,
|
||||||
|
bounce_count: 0,
|
||||||
|
|
||||||
pixel_co: pixel_co,
|
pixel_co: pixel_co,
|
||||||
lds_offset: lds_offset,
|
lds_offset: lds_offset,
|
||||||
dim_offset: Cell::new(6),
|
dim_offset: Cell::new(6),
|
||||||
round: 0,
|
|
||||||
time: time,
|
time: time,
|
||||||
wavelength: wavelength,
|
wavelength: wavelength,
|
||||||
interaction: surface::SurfaceIntersection::Miss,
|
|
||||||
|
next_bounce_ray: None,
|
||||||
|
next_attentuation_fac: Float4::splat(1.0),
|
||||||
|
|
||||||
light_attenuation: Float4::splat(1.0),
|
light_attenuation: Float4::splat(1.0),
|
||||||
pending_color_addition: Float4::splat(0.0),
|
pending_color_addition: Float4::splat(0.0),
|
||||||
color: Float4::splat(0.0),
|
color: Float4::splat(0.0),
|
||||||
|
@ -349,97 +366,133 @@ impl LightPath {
|
||||||
isect: &surface::SurfaceIntersection,
|
isect: &surface::SurfaceIntersection,
|
||||||
ray: &mut Ray)
|
ray: &mut Ray)
|
||||||
-> bool {
|
-> bool {
|
||||||
self.round += 1;
|
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
|
||||||
|
|
||||||
// Result of shading ray, prepare light ray
|
// Prepare light ray
|
||||||
if self.round % 2 == 1 {
|
let light_n = self.next_lds_samp();
|
||||||
if let &surface::SurfaceIntersection::Hit { intersection_data: ref idata,
|
let light_uvw =
|
||||||
ref closure } = isect {
|
(self.next_lds_samp(), self.next_lds_samp(), self.next_lds_samp());
|
||||||
// Hit something! Do the stuff
|
xform_stack.clear();
|
||||||
self.interaction = *isect; // Store interaction for use in next phase
|
let found_light = if let Some((light_color,
|
||||||
|
shadow_vec,
|
||||||
|
light_pdf,
|
||||||
|
light_sel_pdf,
|
||||||
|
is_infinite)) =
|
||||||
|
scene.sample_lights(xform_stack,
|
||||||
|
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 = {
|
||||||
|
let material = closure.as_surface_closure();
|
||||||
|
let la =
|
||||||
|
material.evaluate(ray.dir, shadow_vec, idata.nor, self.wavelength);
|
||||||
|
light_color.e * la.e * self.light_attenuation /
|
||||||
|
(light_pdf * light_sel_pdf)
|
||||||
|
};
|
||||||
|
|
||||||
// Prepare light ray
|
// Calculate the shadow ray for testing if the light is
|
||||||
let light_n = self.next_lds_samp();
|
// in shadow or not.
|
||||||
let light_uvw = (self.next_lds_samp(), self.next_lds_samp(), self.next_lds_samp());
|
// TODO: use proper ray offsets for avoiding self-shadowing
|
||||||
xform_stack.clear();
|
// rather than this hacky stupid stuff.
|
||||||
if let Some((light_color, shadow_vec, light_pdf, light_sel_pdf, is_infinite)) =
|
*ray = Ray::new(idata.pos + shadow_vec.normalized() * 0.001,
|
||||||
scene.sample_lights(xform_stack,
|
shadow_vec,
|
||||||
light_n,
|
|
||||||
light_uvw,
|
|
||||||
self.wavelength,
|
|
||||||
self.time,
|
self.time,
|
||||||
isect) {
|
true);
|
||||||
// Calculate and store the light that will be contributed
|
|
||||||
// to the film plane if the light is not in shadow.
|
// For distant lights
|
||||||
self.pending_color_addition = {
|
if is_infinite {
|
||||||
let material = closure.as_surface_closure();
|
ray.max_t = std::f32::INFINITY;
|
||||||
let la = material.evaluate(ray.dir, shadow_vec, idata.nor, self.wavelength);
|
}
|
||||||
light_color.e * la.e * self.light_attenuation / (light_pdf * light_sel_pdf)
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate the shadow ray for testing if the light is
|
// Prepare bounce ray
|
||||||
// in shadow or not.
|
let do_bounce = if self.bounce_count < 2 {
|
||||||
// TODO: use proper ray offsets for avoiding self-shadowing
|
self.bounce_count += 1;
|
||||||
// rather than this hacky stupid stuff.
|
|
||||||
*ray = Ray::new(idata.pos + shadow_vec.normalized() * 0.001,
|
|
||||||
shadow_vec,
|
|
||||||
self.time,
|
|
||||||
true);
|
|
||||||
|
|
||||||
// For distant lights
|
// Sample material
|
||||||
if is_infinite {
|
let (dir, filter, pdf) = {
|
||||||
ray.max_t = std::f32::INFINITY;
|
let material = closure.as_surface_closure();
|
||||||
|
let u = self.next_lds_samp();
|
||||||
|
let v = self.next_lds_samp();
|
||||||
|
material.sample(idata.incoming, idata.nor, (u, v), self.wavelength)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Account for the additional light attenuation from
|
||||||
|
// this bounce
|
||||||
|
self.next_attentuation_fac = filter.e / pdf;
|
||||||
|
|
||||||
|
// Calculate the ray for this bounce
|
||||||
|
self.next_bounce_ray = Some(Ray::new(idata.pos +
|
||||||
|
dir.normalized() * 0.0001,
|
||||||
|
dir,
|
||||||
|
self.time,
|
||||||
|
false));
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.next_bounce_ray = None;
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Book keeping for next event
|
||||||
|
if found_light && do_bounce {
|
||||||
|
self.event = LightPathEvent::ShadowRay;
|
||||||
|
return true;
|
||||||
|
} else 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_attentuation_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;
|
||||||
|
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_attentuation_fac;
|
||||||
|
self.event = LightPathEvent::BounceRay;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
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;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Result of light ray, prepare shading ray
|
|
||||||
else if self.round % 2 == 0 {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate bounced lighting!
|
|
||||||
if self.round < 6 {
|
|
||||||
if let surface::SurfaceIntersection::Hit { intersection_data: ref idata,
|
|
||||||
ref closure } = self.interaction {
|
|
||||||
// Sample material
|
|
||||||
let (dir, filter, pdf) = {
|
|
||||||
let material = closure.as_surface_closure();
|
|
||||||
let u = self.next_lds_samp();
|
|
||||||
let v = self.next_lds_samp();
|
|
||||||
material.sample(idata.incoming, idata.nor, (u, v), self.wavelength)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Account for the additional light attenuation from
|
|
||||||
// this bounce
|
|
||||||
self.light_attenuation *= filter.e / pdf;
|
|
||||||
|
|
||||||
// Calculate the ray for this bounce
|
|
||||||
*ray = Ray::new(idata.pos + dir.normalized() * 0.0001, dir, self.time, false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user