From 4ea2208208272652409ef769fc28d3788b8d722c Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Tue, 6 Jun 2023 17:39:09 -0500 Subject: [PATCH] Feat: Rudimentary dielectric... but broken Dielectric material matching Raytracing in a Weekend book chapter 10.2. But it isn't right. The spheres turn into solid black holes. As I'm making the commit, I've found the problem. I'm separating it out so I can tag it and explore the code a bit more. See the step-by-step changes, and such. --- src/main.rs | 4 ++-- src/material.rs | 18 ++++++++++++++++-- src/vec3.rs | 41 +++++++++++++++++++++++++---------------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/main.rs b/src/main.rs index 13c895f..6bc60b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,8 +34,8 @@ fn main() { // world let mat_ground = Material::Lambertian{ albedo: Vec3::new(0.8, 0.8, 0.0) }; - let mat_center = Material::Lambertian{ albedo: Vec3::new(0.7, 0.3, 0.3) }; - let mat_left = Material::Metal{ albedo: Vec3::new(0.8, 0.8, 0.8), fuzz: 0.3 }; + let mat_center = Material::Dielectric { index_refraction: 1.5 }; + let mat_left = Material::Dielectric { index_refraction: 1.5 }; let mat_right = Material::Metal{ albedo: Vec3::new(0.8, 0.6, 0.2), fuzz: 1.0 }; let mut world = HittableList::new(); diff --git a/src/material.rs b/src/material.rs index bf5954c..b13e8c9 100644 --- a/src/material.rs +++ b/src/material.rs @@ -11,8 +11,9 @@ use rand::distributions::Uniform; #[derive(Copy, Clone, Debug)] pub enum Material{ - Lambertian{ albedo: Vec3 }, - Metal{ albedo:Vec3, fuzz: f32 }, + Lambertian { albedo: Vec3 }, + Metal { albedo:Vec3, fuzz: f32 }, + Dielectric { index_refraction: f32 }, } impl Material { @@ -58,6 +59,19 @@ impl Material { *attenuation = *albedo; return Vec3::dot(scattered.dir, rec.normal) > 0.0; }, + Material::Dielectric { index_refraction } => { + *attenuation = Vec3::ones(); + let refraction_ratio = if rec.front_face { 1.0 / index_refraction } else { *index_refraction }; + + let unit_direction = Vec3::as_unit(&ray_in.dir); + let refracted = Vec3::refract(unit_direction, rec.normal, refraction_ratio); + + *scattered = Ray { + orig: rec.p, + dir: refracted + }; + return true; + }, } } } diff --git a/src/vec3.rs b/src/vec3.rs index a91af9e..191886d 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -87,23 +87,30 @@ impl Vec3{ let g = (self.y * scale).sqrt(); let b = (self.z * scale).sqrt(); - let ir = (Vec3::clamp(r, 0.0, 0.999) * 256.0) as i32; - let ig = (Vec3::clamp(g, 0.0, 0.999) * 256.0) as i32; - let ib = (Vec3::clamp(b, 0.0, 0.999) * 256.0) as i32; + let ir = (clamp(r, 0.0, 0.999) * 256.0) as i32; + let ig = (clamp(g, 0.0, 0.999) * 256.0) as i32; + let ib = (clamp(b, 0.0, 0.999) * 256.0) as i32; format!("{} {} {}", ir, ig, ib) } pub fn near_zero(&self) -> bool { - let epsilon: f32 = 1e-8; + let epsilon: f32 = 1e-4; return - self.x < epsilon && - self.y < epsilon && - self.z < epsilon + self.x.abs() < epsilon && + self.y.abs() < epsilon && + self.z.abs() < epsilon } pub fn reflect(v: Vec3, n: Vec3) -> Vec3 { return v - n * Vec3::dot(v, n) * 2.0; } + + pub fn refract(uv: Vec3, n: Vec3, etai_over_etat: f32) -> Vec3 { + let cos_theta = min(Vec3::dot(-uv, n), 1.0); + let r_out_perp = (uv + n * cos_theta) * etai_over_etat; + let r_out_parallel = n * -(1.0 - r_out_perp.length_squared()).abs().sqrt(); + r_out_perp + r_out_parallel + } pub fn dot(left: Vec3, right: Vec3) -> f32{ left.x * right.x + @@ -124,15 +131,6 @@ impl Vec3{ *v / len } - fn clamp(input: f32, min: f32, max: f32) -> f32 { - if input < min { - return min; - } else if input > max { - return max; - } else { - return input; - } - } } impl Add for Vec3 { type Output = Vec3; @@ -281,6 +279,17 @@ impl Display for Vec3 { } } +pub fn clamp(input: f32, lower: f32, upper: f32) -> f32 { + min(max(input, lower), upper) +} + +pub fn min(a: f32, b: f32) -> f32 { + if a < b { a } else { b } +} + +pub fn max(a: f32, b: f32) -> f32 { + if a > b { a } else { b } +} #[cfg(test)] mod test{