use core::f32::math::sqrt; use rand::RngExt; use serde::Deserialize; use crate::{ objects::{hit::Hit, materials::traits::Material}, ray::Ray, vec3::Colour, }; #[derive(Debug, Deserialize)] pub struct Dielectric { refraction_index: f32, } impl Dielectric { pub fn new(refraction_index: f32) -> Self { Self { refraction_index } } fn reflectance(cos: f32, refraction_index: f32) -> f32 { // Shlick's approximation let mut r0 = (1. - refraction_index) / (1. + refraction_index); r0 *= r0; r0 + (1. - r0) * (1. - cos).powf(5.) } } impl Material for Dielectric { fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Option, Colour)> { let ri = if hit.front_face() { 1. / self.refraction_index } else { self.refraction_index }; let unit = ray.dir().get_unit(); let cos_theta = if -unit.dot(hit.n()) > 1. { 1. } else { -unit.dot(hit.n()) }; let sin_theta = sqrt(1. - cos_theta * cos_theta); let cannot_refract = ri * sin_theta > 1.; let mut rng = rand::rng(); let dir = if cannot_refract || Dielectric::reflectance(cos_theta, ri) > rng.random::() { unit.reflect(hit.n()) } else { unit.refract(hit.n(), ri) }; Some((Some(Ray::new(*hit.p(), dir)), Colour::new(1., 1., 1.))) } }