diff options
author | Julian T <julian@jtle.dk> | 2021-08-01 22:55:07 +0200 |
---|---|---|
committer | Julian T <julian@jtle.dk> | 2021-08-01 22:55:07 +0200 |
commit | 86ad7845219e8db06fe47b62794180e1b40f90a5 (patch) | |
tree | 2fe1de5c4a854522536a397b7913d7c299b35c67 /src/material | |
parent | ae460c3f34838e3baf0ffafe4ccbcf1fbfe03095 (diff) |
Implement dielectric material from RTIAW
Diffstat (limited to 'src/material')
-rw-r--r-- | src/material/dielectric.rs | 59 | ||||
-rw-r--r-- | src/material/mod.rs | 4 |
2 files changed, 61 insertions, 2 deletions
diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs new file mode 100644 index 0000000..41f47c2 --- /dev/null +++ b/src/material/dielectric.rs @@ -0,0 +1,59 @@ +use super::Material; +use crate::core::{min, Vector3f, Spectrum, Ray}; +use crate::world::Intersection; +use crate::sample::Sampler; +use crate::Float; + +pub struct Dielectric { + ratio: Float, +} + +fn reflect(v: Vector3f, n: Vector3f) -> Vector3f { + v - n * (2.0 * v.dot(&n)) +} + +// Implementation from RTIOW +fn refract(v: Vector3f, n: Vector3f, r_ratio: Float, cos_theta: Float) -> Vector3f { + let r_perp = (v + n * cos_theta) * r_ratio; + let r_parallel = n * (-(1.0 - r_perp.len_squared()).abs().sqrt()); + + r_perp + r_parallel +} + +// Schlick Approximation, explained in RTIOW +fn fresnel(cos: Float, ratio: Float) -> Float { + let mut r0 = (1.0-ratio) / (1.0+ratio); + r0 = r0 * r0; + + r0 + (1.0-r0)*(1.0-cos).powi(5) +} + +impl Dielectric { + pub fn new(ratio: Float) -> Self { + Self { ratio } + } +} + +impl Material for Dielectric { + // Implementation from RTIOW + fn scatter(&self, ray: &Ray, i: &Intersection, sampler: &mut dyn Sampler) -> Option<(Spectrum, Ray)> { + let ratio = if i.front {1.0/self.ratio} else {self.ratio}; + + let ray_dir = ray.direction.norm(); + let cos_theta = min((-ray_dir).dot(&i.n), 1.0); + let sin_theta = (1.0 - cos_theta*cos_theta).sqrt(); + + // Test if it is possible for the ray the retract or if it must reflect. + let cannot_refract = (ratio * sin_theta) > 1.0; + let direction = if cannot_refract || (fresnel(cos_theta, ratio) > sampler.get_sample()) { + reflect(ray_dir, i.n) + } else { + refract(ray_dir, i.n, ratio, cos_theta) + }; + + Some(( + Spectrum::WHITE, + Ray::new(i.p, direction), + )) + } +} diff --git a/src/material/mod.rs b/src/material/mod.rs index 3e92bf6..d3c3154 100644 --- a/src/material/mod.rs +++ b/src/material/mod.rs @@ -3,14 +3,14 @@ use crate::world::Intersection; use crate::sample::Sampler; mod lambertian; -mod reflectant; mod diffuse_light; mod sky_light; +mod dielectric; pub use lambertian::Lambertian; -pub use reflectant::Reflectant; pub use diffuse_light::DiffuseLight; pub use sky_light::SkyLight; +pub use dielectric::Dielectric; pub trait Material: Sync + Send { fn scatter(&self, _: &Ray, _: &Intersection, _: &mut dyn Sampler) -> Option<(Spectrum, Ray)> { |