From 1920376e342cc968e00fe2dadf375195fb82d605 Mon Sep 17 00:00:00 2001 From: djairoh Date: Thu, 16 Apr 2026 15:38:01 +0200 Subject: [PATCH] ft (wip): 10: dielectrics --- src/main.rs | 3 ++- src/objects/hit.rs | 10 ++++++++-- src/objects/materials.rs | 1 + src/objects/materials/dielectric.rs | 30 +++++++++++++++++++++++++++++ src/objects/sphere.rs | 12 ++++++++++-- src/vec3.rs | 22 +++++++++++++++++++-- 6 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 src/objects/materials/dielectric.rs diff --git a/src/main.rs b/src/main.rs index 12af2af..1b6d294 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod vec3; use std::sync::Arc; use crate::camera::Camera; +use crate::objects::materials::dielectric::Dielectric; use crate::objects::materials::lambertian::{Lambertian, Metal}; use crate::objects::sphere::Sphere; use crate::ray::Ray; @@ -21,7 +22,7 @@ fn main() { let metal = Arc::new(Metal::rgb(0.7, 0.4, 0.2, 1., 0.1)); let ground = Arc::new(Lambertian::rgb(0.8, 0.8, 0., 1.0)); let center = Arc::new(Lambertian::rgb(0.1, 0.2, 0.5, 1.)); - let left = Arc::new(Metal::rgb(0.8, 0.8, 0.8, 1., 0.3)); + let left = Arc::new(Dielectric::new(1.5)); let right = Arc::new(Metal::rgb(0.8, 0.6, 0.2, 1., 1.0)); let mut world = vec![Sphere::xyz(0., 0.5, -0.8, 0.1, metal.clone())]; diff --git a/src/objects/hit.rs b/src/objects/hit.rs index 633510e..b1caaba 100644 --- a/src/objects/hit.rs +++ b/src/objects/hit.rs @@ -11,15 +11,17 @@ pub struct Hit { p: Vec3, n: Vec3, mat: Arc, + front_face: bool, } impl Hit { - pub fn new(t: f32, p: Vec3, n: Vec3, mat: Arc) -> Self { + pub fn new(t: f32, p: Vec3, n: Vec3, mat: Arc, front_face: bool) -> Self { Self { t: t, p: p, - n: n, + n: if front_face { n } else { -n }, mat: mat, + front_face: front_face, } } @@ -39,6 +41,10 @@ impl Hit { self.mat.clone() } + pub fn front_face(&self) -> bool { + self.front_face + } + pub fn hit_list(hittables: &Vec, r: &Ray) -> Option { let mut closest: Option = None; for hittable in hittables { diff --git a/src/objects/materials.rs b/src/objects/materials.rs index 39a34e0..ba0b2cd 100644 --- a/src/objects/materials.rs +++ b/src/objects/materials.rs @@ -1,2 +1,3 @@ +pub mod dielectric; pub mod lambertian; pub mod traits; diff --git a/src/objects/materials/dielectric.rs b/src/objects/materials/dielectric.rs new file mode 100644 index 0000000..441b252 --- /dev/null +++ b/src/objects/materials/dielectric.rs @@ -0,0 +1,30 @@ +use crate::{ + objects::{hit::Hit, materials::traits::Material}, + ray::Ray, + vec3::Colour, +}; + +pub struct Dielectric { + refraction_index: f32, +} + +impl Dielectric { + pub fn new(refraction_index: f32) -> Self { + Self { + refraction_index: refraction_index, + } + } +} + +impl Material for Dielectric { + fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)> { + let ri = if hit.front_face() { + 1. / self.refraction_index + } else { + self.refraction_index + }; + let unit = ray.dir().get_unit(); + let refr = unit.refract(hit.n(), ri); + Some((Ray::new(*hit.p(), refr), Colour::new(1., 1., 1.))) + } +} diff --git a/src/objects/sphere.rs b/src/objects/sphere.rs index 19bdbee..1a64a09 100644 --- a/src/objects/sphere.rs +++ b/src/objects/sphere.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::objects::hit::Hit; use crate::objects::materials::traits::Material; use crate::objects::traits::Hittable; +use crate::ray::Ray; use crate::Vec3; pub struct Sphere { @@ -31,7 +32,7 @@ impl Sphere { } impl Hittable for Sphere { - fn hit(&self, r: &crate::ray::Ray) -> Option { + fn hit(&self, r: &Ray) -> Option { let oc = self.center - r.origin(); let a = r.dir().length_squared(); let h = r.dir().dot(&oc); @@ -43,7 +44,14 @@ impl Hittable for Sphere { } else { let t = (h - sqrt(d)) / a; let p = r.at(t); - Some(Hit::new(t, p, self.normal_at(&p), self.material.clone())) + let out_n = (p - self.center) / self.radius; + Some(Hit::new( + t, + p, + self.normal_at(&p), + self.material.clone(), + out_n.dot(r.dir()) < 0., + )) } } diff --git a/src/vec3.rs b/src/vec3.rs index 6b355b9..0e35b8b 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -101,8 +101,18 @@ impl Vec3 { && default().is_close(self.b, 0.) } - pub fn reflect(&self, o: &Vec3) -> Vec3 { - *self - 2. * self.dot(o) * o + pub fn reflect(&self, n: &Self) -> Self { + *self - 2. * self.dot(n) * n + } + + pub fn refract(&self, n: &Self, etai_over_etat: f32) -> Self { + let mut cos_theta = -self.dot(n); + cos_theta = if cos_theta > 1.0 { 1.0 } else { cos_theta }; + + let r_out_perp = etai_over_etat * (*self + cos_theta * n); + let r_out_parr = -sqrt((1. - r_out_perp.length_squared()).abs()) * n; + + return r_out_perp + r_out_parr; } pub fn output(self) -> image::Rgb { @@ -139,6 +149,14 @@ impl Vec3 { } } +impl Neg for &Vec3 { + type Output = Vec3; + + fn neg(self) -> Self::Output { + -*self + } +} + impl Neg for Vec3 { type Output = Self;