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);
let (new_direction, _) = sample_hemisphere(normal);
let new_direction = sample_hemisphere(normal);
// Calculate the incoming light along the new ray
origin = hit_pos + new_direction.as_ref() * 0.001;
direction = new_direction;

View file

@ -110,8 +110,7 @@ impl Pathtracer {
let brdf = properties.diffuse;
// Pick a new direction
let normal = obj.shape.normal(&hit_pos);
let (new_direction, weight) = sample_hemisphere(normal);
let cos_new_ray = new_direction.dot(&normal);
let new_direction = sample_hemisphere(normal);
// Calculate the incoming light along the new ray
let new_ray = Ray::new(hit_pos + new_direction.as_ref() * 0.001, new_direction);
let incoming = self
@ -120,7 +119,8 @@ impl Pathtracer {
self.radiance(new_ray, t, obj, limit - 1)
});
// 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)> {

View file

@ -70,9 +70,9 @@ impl RefractionInfo {
}
}
/// Returns a random ray in the hemisphere described by a normal unit-vector, and the probability
/// to have picked that direction.
pub fn sample_hemisphere(normal: Unit<Vector>) -> (Unit<Vector>, f32) {
/// Returns a random ray in the hemisphere described by a normal unit-vector
/// It is cosine-sampled, which is convenient for path-tracing.
pub fn sample_hemisphere(normal: Unit<Vector>) -> Unit<Vector> {
let mut rng = thread_rng();
let azimuth = rng.gen::<f32>() * std::f32::consts::PI * 2.;
// 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);
// 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.y + y * normal.y + z * normal_t.y,
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 {