diff options
author | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-03 01:55:16 +0700 |
---|---|---|
committer | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-03 01:55:16 +0700 |
commit | 988a418f8907fb5e3abb77222929d6ab7b60c1b6 (patch) | |
tree | b2adb4d4d08dca50a0d57b8a580c755b84ad9c04 | |
parent | ab0b3f165788c5d79b2d159aeefda8c8947b68ae (diff) |
upd transparent material
-rw-r--r-- | src/calculus.rs | 21 | ||||
-rw-r--r-- | src/main.rs | 14 | ||||
-rw-r--r-- | src/material.rs | 37 |
3 files changed, 60 insertions, 12 deletions
diff --git a/src/calculus.rs b/src/calculus.rs index 568eb60..2e8a1d5 100644 --- a/src/calculus.rs +++ b/src/calculus.rs @@ -119,6 +119,19 @@ pub mod calculus { ) ) } + + pub fn refract(&self, normal: &Self, etai_over_etat: f32) -> Self { + let cos_theta = f32::min( + 1.0, + self.scalar_mul(-1.0).dot_prod(&normal) + ); + let r_out_perp = self + .add(&normal.scalar_mul(cos_theta)) + .scalar_mul(etai_over_etat); + let f = (1.0 - r_out_perp.mag_sqr()).abs().sqrt(); + let r_out_parallel = normal.scalar_mul(-1.0 * f); + r_out_perp.add(&r_out_parallel) + } } pub struct Ray { @@ -133,7 +146,13 @@ pub mod calculus { } pub fn reflect(&self, normal: &Vec3) -> Vec3 { - self.direction.reflect(&normal) + // return unit direction vector + self.direction.reflect(&normal).unit() + } + + pub fn refract(&self, normal: &Vec3, etai_over_etat: f32) -> Vec3 { + // return unit direction vector + self.direction.unit().refract(&normal, etai_over_etat) } } diff --git a/src/main.rs b/src/main.rs index cc5d6b6..5772ffb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,21 +18,23 @@ fn main() { let mut world = HittableList::new(); let ground = Material::new(Color::from_name(ColorName::Maroon), MaterialType::Diffuse); - let blue = Material::new(Color::new(0.1, 0.2, 0.5), MaterialType::Diffuse); - let steel = Material::new(Color::from_name(ColorName::Silver), MaterialType::Metal(0.1)); - let gold = Material::new(Color::from_name(ColorName::Yellow), MaterialType::Metal(0.0)); + let stone = Material::new(Color::from_name(ColorName::Gray), MaterialType::Diffuse); + let steel = Material::new(Color::from_name(ColorName::Silver), MaterialType::Metallic(0.1)); + // let gold = Material::new(Color::from_name(ColorName::Yellow), MaterialType::Metallic(0.0)); + let glass = Material::new(Color::from_name(ColorName::White), MaterialType::Transparent(1.5)); + let bubble = Material::new(Color::from_name(ColorName::White), MaterialType::Transparent(1.0 / 1.3)); world.push( Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0, ground) ); world.push( - Sphere::new(Point3::new(0.0, 0.0, -1.2), 0.5, blue) + Sphere::new(Point3::new(0.0, 0.0, -1.2), 0.5, stone) ); world.push( - Sphere::new(Point3::new(-1.0, 0.0, -1.0), 0.5, steel) + Sphere::new(Point3::new(-1.0, 0.0, -1.0), 0.5, glass) ); world.push( - Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, gold) + Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, steel) ); let camera = Camera::new(); diff --git a/src/material.rs b/src/material.rs index a654f4d..833ef19 100644 --- a/src/material.rs +++ b/src/material.rs @@ -1,3 +1,4 @@ +use rand::Rng; use crate::calculus::calculus::{Ray, Vec3}; use crate::common::Color; use crate::object::HitRecord; @@ -5,7 +6,8 @@ use crate::object::HitRecord; #[derive(Clone)] pub enum MaterialType { Diffuse, - Metal(f32), // color fuzz + Metallic(f32), // fuzz + Transparent(f32), // refraction index } #[derive(Clone)] @@ -17,9 +19,9 @@ pub struct Material { impl Material { pub fn new(albedo: Color, material_type: MaterialType) -> Self { let mut material_type = material_type; - if let MaterialType::Metal(fuzz) = material_type { + if let MaterialType::Metallic(fuzz) = material_type { let fuzz = if fuzz < 1.0 { fuzz } else { fuzz }; - material_type = MaterialType::Metal(fuzz); + material_type = MaterialType::Metallic(fuzz); } Self { albedo, material_type } } @@ -34,11 +36,30 @@ impl Material { scatter_direction } } - MaterialType::Metal(fuzz) => { + MaterialType::Metallic(fuzz) => { let mut reflected = r_in.reflect(&rec.normal); - reflected.unit().add(&Vec3::random_unit().scalar_mul(fuzz)) + reflected.add(&Vec3::random_unit().scalar_mul(fuzz)) } + MaterialType::Transparent(refraction_index) => { + let ri = if rec.front_face { + 1.0 / refraction_index + } else { + refraction_index + }; + let cos_theta = f32::min( + r_in.direction.unit().scalar_mul(-1.0).dot_prod(&rec.normal), + 1.0 + ); + let sin_theta = (1.0 - cos_theta * cos_theta).sqrt(); + let cannot_refract = ri * sin_theta > 1.0; + let random: f32 = rand::rng().random(); + if cannot_refract || Self::reflectance(cos_theta, ri) > random { + r_in.direction.unit().reflect(&rec.normal) + } else { + r_in.refract(&rec.normal, ri) + } + } }; scattered.origin = rec.position; attenuation.r = self.albedo.r; @@ -46,4 +67,10 @@ impl Material { attenuation.b = self.albedo.b; true } + + fn reflectance(cosine: f32, refraction_index: f32) -> f32 { + let mut r0 = (1.0 - refraction_index) / (1.0 + refraction_index); + r0 = r0 * r0; + r0 + (1.0 - r0) * (1.0 - cosine).powi(5) + } }
\ No newline at end of file |