diff options
author | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-02 16:56:59 +0700 |
---|---|---|
committer | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-02 16:56:59 +0700 |
commit | 93b24b9d01f806cf69ecee86fada9e5b9bf06182 (patch) | |
tree | c4c941acdeced6cb5b9cc51eedabc994ceda0b38 | |
parent | d618968b9577cbaf6306f42157be19bd2a6a6aa0 (diff) |
material
-rw-r--r-- | src/calculus.rs | 18 | ||||
-rw-r--r-- | src/camera.rs | 22 | ||||
-rw-r--r-- | src/main.rs | 10 | ||||
-rw-r--r-- | src/material.rs | 41 | ||||
-rw-r--r-- | src/object.rs | 14 |
5 files changed, 97 insertions, 8 deletions
diff --git a/src/calculus.rs b/src/calculus.rs index e1e9caf..568eb60 100644 --- a/src/calculus.rs +++ b/src/calculus.rs @@ -105,6 +105,20 @@ pub mod calculus { z: self.z / mag, } } + + pub fn is_near_zero(&self) -> bool { + self.x.abs() < f32::EPSILON && + self.y.abs() < f32::EPSILON && + self.z.abs() < f32::EPSILON + } + + pub fn reflect(&self, normal: &Self) -> Self { + self.sub( + &normal.scalar_mul( + 2.0 * self.dot_prod(&normal) + ) + ) + } } pub struct Ray { @@ -117,6 +131,10 @@ pub mod calculus { // Get parametric location self.origin.add(&self.direction.scalar_mul(t)) } + + pub fn reflect(&self, normal: &Vec3) -> Vec3 { + self.direction.reflect(&normal) + } } pub fn deg2rad(deg: f32) -> f32 { diff --git a/src/camera.rs b/src/camera.rs index 63e0097..a133035 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,6 +1,7 @@ use crate::calculus::calculus::{sample_square, Point3, Ray, Vec3}; use crate::common::{get_image_height, Color, DisplayBuffer, Pixel, ASPECT_RATIO, CAMERA_CENTER, FOCAL_LENGTH, IMG_WIDTH, MAX_DEPTH, SAMPLES_PER_PIXEL, VIEWPORT_HEIGHT}; use crate::interval::Interval; +use crate::material::{Material, MaterialType}; use crate::object::{HitRecord, Hittable, HittableList}; pub struct Camera { @@ -86,10 +87,23 @@ impl Camera { let ray_t = Interval::new(0.001, f32::INFINITY); if world.hit(ray, ray_t, &mut rec) { // let direction = Vec3::random_on_hemisphere(&rec.normal); - let direction = rec.normal.add(&Vec3::random_unit()); - let origin = rec.position.clone(); - let r = Ray { origin, direction }; - return self.ray_color(&r, world, depth - 1).mul_scalar(0.9); + let material = Material::new( + rec.color.clone(), + rec.material.clone() + ); + let mut scattered: Ray = Ray { + origin: Vec3::random_unit(), + direction: Vec3::random_unit(), + }/* value */; + let mut attenuation: Color = Color::new(0.0, 0.0, 0.0); + if material.scatter(ray, &rec, &mut attenuation, &mut scattered) { + let attenuated = self.ray_color(&mut scattered, &world, depth - 1); + attenuation.r *= attenuated.r; + attenuation.r *= attenuated.g; + attenuation.r *= attenuated.b; + return attenuation; + } + return Color::new(0.0, 0.0, 0.0); } let unit_direction = ray.direction.unit(); diff --git a/src/main.rs b/src/main.rs index 73888c2..7c6c8f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,12 @@ mod calculus; mod camera; mod object; mod interval; +mod material; use crate::calculus::calculus::Point3; use crate::common::*; use crate::camera::Camera; +use crate::material::{Material, MaterialType}; use crate::object::{HittableList, Sphere}; use crate::view::{render_viewer, View}; @@ -16,11 +18,15 @@ fn main() { let mut world = HittableList::new(); world.push( - Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5) + Sphere::new(Point3::new(0.6, -0.3, -1.0), 0.3, MaterialType::Metal, Color::new(0.8, 0.0, 0.0)) ); world.push( - Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0) + Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5, MaterialType::Diffuse, Color::new(0.4, 0.4, 0.4)) + ); + + world.push( + Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0, MaterialType::Diffuse, Color::new(0.2, 0.2, 0.2)) ); let camera = Camera::new(); diff --git a/src/material.rs b/src/material.rs new file mode 100644 index 0000000..2b3deae --- /dev/null +++ b/src/material.rs @@ -0,0 +1,41 @@ +use crate::calculus::calculus::{Ray, Vec3}; +use crate::common::Color; +use crate::object::HitRecord; + +#[derive(Clone)] +pub enum MaterialType { + Diffuse, + Metal, +} + +pub struct Material { + pub material_type: MaterialType, + pub albedo: Color +} + +impl Material { + pub fn new(albedo: Color, material_type: MaterialType) -> Self { + Self { albedo, material_type } + } + + pub fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + scattered.direction = match self.material_type { + MaterialType::Diffuse => { + let scatter_direction = rec.normal.add(&Vec3::random_unit()); + if scatter_direction.is_near_zero() { + rec.normal.clone() + } else { + scatter_direction + } + } + MaterialType::Metal => { + r_in.reflect(&rec.normal) + } + }; + scattered.origin = rec.position; + attenuation.r = self.albedo.r; + attenuation.g = self.albedo.g; + attenuation.b = self.albedo.b; + true + } +}
\ No newline at end of file diff --git a/src/object.rs b/src/object.rs index c1bce61..d9e2cc4 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,5 +1,7 @@ use crate::calculus::calculus::{Point3, Ray, Vec3}; +use crate::common::Color; use crate::interval::Interval; +use crate::material::MaterialType; #[derive(Clone)] pub struct HitRecord { @@ -7,6 +9,8 @@ pub struct HitRecord { pub normal: Vec3, pub t: f32, pub front_face: bool, + pub material: MaterialType, + pub color: Color, } impl Default for HitRecord { @@ -16,6 +20,8 @@ impl Default for HitRecord { normal: Vec3 {x:0.0, y:0.0, z:0.0}, t: 0.0, front_face: false, + material: MaterialType::Diffuse, + color:Color::new(0.0, 0.0, 0.0), } } } @@ -34,12 +40,14 @@ pub trait Hittable { pub struct Sphere { center: Point3, radius: f32, + material: MaterialType, + color: Color } impl Sphere { - pub fn new(center: Vec3, radius: f32) -> Self { + pub fn new(center: Vec3, radius: f32, material: MaterialType, color: Color) -> Self { let radius = f32::max(0.0, radius); - Self { center, radius } + Self { center, radius, material, color } } } @@ -70,6 +78,8 @@ impl Hittable for Sphere { .sub(&self.center) .scalar_mul(1.0 / self.radius); rec.set_face_normal(r, outward_normal); + rec.material = self.material.clone(); + rec.color = self.color.clone(); true } |