vanrijn/src/materials/reflective_material.rs

49 lines
1.8 KiB
Rust

use crate::colour::{Photon, Spectrum};
use crate::math::Vec3;
use std::fmt::Debug;
use super::{Material, MaterialSampleResult};
#[derive(Debug)]
pub struct ReflectiveMaterial {
pub colour: Spectrum,
pub diffuse_strength: f64,
pub reflection_strength: f64,
}
impl Material for ReflectiveMaterial {
fn bsdf<'a>(&'a self) -> Box<dyn Fn(&Vec3, &Vec3, &Photon) -> Photon + 'a> {
Box::new(move |w_o: &Vec3, w_i: &Vec3, photon_in: &Photon| {
if w_i.z() <= 0.0 || w_o.z() <= 0.0 {
Photon {
wavelength: photon_in.wavelength,
intensity: 0.0,
}
} else {
let reflection_vector = Vec3::new(-w_o.x(), -w_o.y(), w_o.z());
let mut photon_out = self.colour.scale_photon(photon_in);
photon_out.intensity *= self.diffuse_strength;
let sigma = 0.05;
let two = 2.0;
// These are normalized vectors, but sometimes rounding errors cause the
// dot product to be slightly above 1 or below 0. The call to clamp
// ensures the values stay within the domain of acos,
let theta = w_i.dot(&reflection_vector).clamp(0.0, 1.0).abs().acos();
let reflection_factor =
self.reflection_strength * (-(theta.powf(two)) / (two * sigma * sigma)).exp();
photon_out.intensity =
photon_out.intensity * (1.0 - reflection_factor) + reflection_factor;
photon_out
}
})
}
fn sample(&self, w_o: &Vec3, _photon: &Photon) -> MaterialSampleResult {
MaterialSampleResult {
direction: Vec3::new(-w_o.x(), -w_o.y(), w_o.z()),
pdf: 1.0,
}
}
}