Add SmoothTransparentDialectric material
This commit is contained in:
parent
db2d1806a3
commit
7c82605d98
|
|
@ -15,6 +15,9 @@ pub use phong_material::PhongMaterial;
|
|||
pub mod reflective_material;
|
||||
pub use reflective_material::ReflectiveMaterial;
|
||||
|
||||
pub mod smooth_transparent_dialectric;
|
||||
pub use smooth_transparent_dialectric::SmoothTransparentDialectric;
|
||||
|
||||
pub trait Material: Debug + Sync + Send {
|
||||
fn bsdf<'a>(&'a self) -> Box<dyn Fn(&Vec3, &Vec3, &Photon) -> Photon + 'a>;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
use crate::colour::{Photon, Spectrum};
|
||||
use crate::materials::Material;
|
||||
use crate::math::Vec3;
|
||||
|
||||
use rand::random;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FresnelResult {
|
||||
reflection_direction: Vec3,
|
||||
reflection_strength: f64,
|
||||
transmission_direction: Vec3,
|
||||
transmission_strength: f64,
|
||||
}
|
||||
|
||||
fn fresnel(w_i: &Vec3, eta1: f64, eta2: f64) -> FresnelResult {
|
||||
let normal = if w_i.z() > 0.0 {
|
||||
Vec3::unit_z()
|
||||
} else {
|
||||
-Vec3::unit_z()
|
||||
};
|
||||
let reflection_direction = Vec3::new(-w_i.x(), -w_i.y(), w_i.z());
|
||||
let r = eta1 / eta2;
|
||||
let cos_theta1 = normal.dot(w_i);
|
||||
let cos_theta2_squared = 1.0 - r * r * (1.0 - cos_theta1 * cos_theta1);
|
||||
let mut result = if cos_theta2_squared >= 0.0 {
|
||||
let cos_theta2 = cos_theta2_squared.sqrt();
|
||||
let reflection_strength_parallel_sqrt =
|
||||
(eta1 * cos_theta2 - eta2 * cos_theta1) / (eta1 * cos_theta2 + eta2 * cos_theta1);
|
||||
let reflection_strength_perpendicular_sqrt =
|
||||
(eta1 * cos_theta1 - eta2 * cos_theta2) / (eta1 * cos_theta1 + eta2 * cos_theta2);
|
||||
let reflection_strength = 0.5
|
||||
* (reflection_strength_parallel_sqrt * reflection_strength_parallel_sqrt
|
||||
+ reflection_strength_perpendicular_sqrt * reflection_strength_perpendicular_sqrt);
|
||||
let transmission_direction =
|
||||
(-r * w_i + (r * cos_theta1 - cos_theta2) * normal).normalize();
|
||||
let transmission_strength = 1.0 - reflection_strength;
|
||||
FresnelResult {
|
||||
reflection_direction,
|
||||
reflection_strength,
|
||||
transmission_direction,
|
||||
transmission_strength,
|
||||
}
|
||||
} else {
|
||||
let reflection_strength = 1.0;
|
||||
let transmission_strength = 0.0;
|
||||
let transmission_direction = Default::default();
|
||||
FresnelResult {
|
||||
reflection_direction,
|
||||
reflection_strength,
|
||||
transmission_direction,
|
||||
transmission_strength,
|
||||
}
|
||||
};
|
||||
if w_i.z() < 0.0 {
|
||||
result.reflection_direction.coords[2] *= -1.0;
|
||||
result.transmission_direction.coords[2] *= -1.0;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SmoothTransparentDialectric {
|
||||
eta: Spectrum,
|
||||
}
|
||||
|
||||
impl SmoothTransparentDialectric {
|
||||
pub fn new(eta: Spectrum) -> SmoothTransparentDialectric {
|
||||
SmoothTransparentDialectric { eta }
|
||||
}
|
||||
}
|
||||
|
||||
impl Material for SmoothTransparentDialectric {
|
||||
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| {
|
||||
let (eta1, eta2) = if w_i.z() >= 0.0 {
|
||||
(1.0, self.eta.intensity_at_wavelength(photon_in.wavelength))
|
||||
} else {
|
||||
(self.eta.intensity_at_wavelength(photon_in.wavelength), 1.0)
|
||||
};
|
||||
let fresnel = fresnel(w_i, eta1, eta2);
|
||||
if (*w_o - fresnel.reflection_direction).norm_squared() < 0.0000000001 {
|
||||
photon_in.scale_intensity(fresnel.reflection_strength)
|
||||
} else if (*w_o - fresnel.transmission_direction).norm_squared() < 0.0000000001 {
|
||||
photon_in.scale_intensity(fresnel.transmission_strength)
|
||||
} else {
|
||||
/*dbg!(
|
||||
w_o,
|
||||
fresnel.reflection_direction,
|
||||
fresnel.transmission_direction
|
||||
);*/
|
||||
photon_in.set_intensity(0.0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn sample(&self, w_i: &Vec3, photon: &Photon) -> Vec3 {
|
||||
let (eta1, eta2) = if w_i.z() >= 0.0 {
|
||||
(1.0, self.eta.intensity_at_wavelength(photon.wavelength))
|
||||
} else {
|
||||
(self.eta.intensity_at_wavelength(photon.wavelength), 1.0)
|
||||
};
|
||||
let fresnel = fresnel(w_i, eta1, eta2);
|
||||
if fresnel.transmission_strength <= 0.0000000001 {
|
||||
fresnel.reflection_direction
|
||||
} else if fresnel.reflection_strength <= 0.0000000001 || random() {
|
||||
fresnel.transmission_direction
|
||||
} else {
|
||||
fresnel.reflection_direction
|
||||
}
|
||||
}
|
||||
|
||||
fn pdf(&self, _w_i: &Vec3, _w_o: &Vec3) -> f64 {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue