library: render: take advantage of cosine-weighted

This commit is contained in:
Bruno BELANYI 2020-05-09 16:28:20 +02:00
parent 311b7cd03b
commit 7567b93f9c
3 changed files with 11 additions and 13 deletions

View file

@ -48,7 +48,7 @@ impl BidirectionalPathtracer {
res.push_point(p); res.push_point(p);
let (new_direction, _) = sample_hemisphere(normal); let new_direction = sample_hemisphere(normal);
// Calculate the incoming light along the new ray // Calculate the incoming light along the new ray
origin = hit_pos + new_direction.as_ref() * 0.001; origin = hit_pos + new_direction.as_ref() * 0.001;
direction = new_direction; direction = new_direction;

View file

@ -110,8 +110,7 @@ impl Pathtracer {
let brdf = properties.diffuse; let brdf = properties.diffuse;
// Pick a new direction // Pick a new direction
let normal = obj.shape.normal(&hit_pos); let normal = obj.shape.normal(&hit_pos);
let (new_direction, weight) = sample_hemisphere(normal); let new_direction = sample_hemisphere(normal);
let cos_new_ray = new_direction.dot(&normal);
// Calculate the incoming light along the new ray // Calculate the incoming light along the new ray
let new_ray = Ray::new(hit_pos + new_direction.as_ref() * 0.001, new_direction); let new_ray = Ray::new(hit_pos + new_direction.as_ref() * 0.001, new_direction);
let incoming = self let incoming = self
@ -120,7 +119,8 @@ impl Pathtracer {
self.radiance(new_ray, t, obj, limit - 1) self.radiance(new_ray, t, obj, limit - 1)
}); });
// Put it all together // Put it all together
properties.emitted + (brdf * incoming * cos_new_ray * weight) // The weight of the sample and the cosine of the new ray cancel each other out
properties.emitted + (brdf * incoming)
} }
fn cast_ray(&self, ray: Ray) -> Option<(f32, &Object)> { fn cast_ray(&self, ray: Ray) -> Option<(f32, &Object)> {

View file

@ -70,9 +70,9 @@ impl RefractionInfo {
} }
} }
/// Returns a random ray in the hemisphere described by a normal unit-vector, and the probability /// Returns a random ray in the hemisphere described by a normal unit-vector
/// to have picked that direction. /// It is cosine-sampled, which is convenient for path-tracing.
pub fn sample_hemisphere(normal: Unit<Vector>) -> (Unit<Vector>, f32) { pub fn sample_hemisphere(normal: Unit<Vector>) -> Unit<Vector> {
let mut rng = thread_rng(); let mut rng = thread_rng();
let azimuth = rng.gen::<f32>() * std::f32::consts::PI * 2.; let azimuth = rng.gen::<f32>() * std::f32::consts::PI * 2.;
// Cosine weighted importance sampling // Cosine weighted importance sampling
@ -93,15 +93,13 @@ pub fn sample_hemisphere(normal: Unit<Vector>) -> (Unit<Vector>, f32) {
let normal_b = normal.cross(&normal_t); let normal_b = normal.cross(&normal_t);
// Perform the matrix calculation by hand... // Perform the matrix calculation by hand...
let scattered = Unit::new_normalize(Vector::new( // The probability to have picked the ray is inversely proportional to cosine of the angle with
// the normal
Unit::new_normalize(Vector::new(
x * normal_b.x + y * normal.x + z * normal_t.x, x * normal_b.x + y * normal.x + z * normal_t.x,
x * normal_b.y + y * normal.y + z * normal_t.y, x * normal_b.y + y * normal.y + z * normal_t.y,
x * normal_b.z + y * normal.z + z * normal_t.z, x * normal_b.z + y * normal.z + z * normal_t.z,
)); ))
// The probability to have picked the ray is inversely proportional to cosine of the angle with
// the normal
(scattered, (1. / scattered.dot(&normal)).min(f32::MAX))
} }
pub fn buffer_to_image(buffer: &[LinearColor], passes: u32, width: u32, height: u32) -> RgbImage { pub fn buffer_to_image(buffer: &[LinearColor], passes: u32, width: u32, height: u32) -> RgbImage {