summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-03 01:55:16 +0700
committerRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-03 01:55:16 +0700
commit988a418f8907fb5e3abb77222929d6ab7b60c1b6 (patch)
treeb2adb4d4d08dca50a0d57b8a580c755b84ad9c04
parentab0b3f165788c5d79b2d159aeefda8c8947b68ae (diff)
upd transparent material
-rw-r--r--src/calculus.rs21
-rw-r--r--src/main.rs14
-rw-r--r--src/material.rs37
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