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.
This commit is contained in:
2023-06-06 17:39:09 -05:00
parent ef5e3fa388
commit 4ea2208208
3 changed files with 43 additions and 20 deletions

View File

@@ -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();

View File

@@ -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;
},
}
}
}

View File

@@ -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{