From 03e5a88f9b7da79749370685e8f5afaf03a25b4a Mon Sep 17 00:00:00 2001 From: Sakarias Johansson Date: Mon, 16 Jan 2023 20:58:55 +0100 Subject: =?UTF-8?q?=F0=9F=8E=A8=20Add=20dialectric=20material?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- racer-tracer/src/material/dialectric.rs | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 racer-tracer/src/material/dialectric.rs (limited to 'racer-tracer/src/material') diff --git a/racer-tracer/src/material/dialectric.rs b/racer-tracer/src/material/dialectric.rs new file mode 100644 index 0000000..5f3aa02 --- /dev/null +++ b/racer-tracer/src/material/dialectric.rs @@ -0,0 +1,53 @@ +use crate::{ + material::Material, + ray::Ray, + util::random_double, + vec3::{dot, reflect, refract, Color}, +}; + +pub struct Dialectric { + refraction_index: f64, +} + +impl Dialectric { + pub fn new(refraction_index: f64) -> Self { + Self { refraction_index } + } + + fn reflectance(cosine: f64, refraction_index: f64) -> f64 { + // Schlick approximation + let mut r0 = (1.0 - refraction_index) / (1.0 + refraction_index); + r0 = r0 * r0; + r0 + (1.0 - r0) * (1.0 - cosine).powf(5.0) + } +} + +impl Material for Dialectric { + fn scatter( + &self, + ray: &crate::ray::Ray, + rec: &crate::geometry::HitRecord, + ) -> Option<(Ray, Color)> { + let refraction_ratio = if rec.front_face { + 1.0 / self.refraction_index + } else { + self.refraction_index + }; + + let unit_direction = &ray.direction().unit_vector(); + let cos_theta = f64::min(dot(&-unit_direction, &rec.normal), 1.0); + let sin_theta = f64::sqrt(1.0 - cos_theta * cos_theta); + + let cannot_refract = refraction_ratio * sin_theta > 1.0; + + let direction = if cannot_refract + || Dialectric::reflectance(cos_theta, refraction_ratio) > random_double() + { + reflect(unit_direction, &rec.normal) + } else { + refract(unit_direction, &rec.normal, refraction_ratio) + }; + + Some((Ray::new(rec.point, direction), Color::new(1.0, 1.0, 1.0))) + } +} -- cgit v1.2.3