diff options
author | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-03 00:15:55 +0700 |
---|---|---|
committer | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2025-03-03 00:15:55 +0700 |
commit | ab0b3f165788c5d79b2d159aeefda8c8947b68ae (patch) | |
tree | fc19c8105c401685f7668ed663050366338a2d27 | |
parent | 7301f5af4fc7cb7bc13a9d559183f2f095de47d0 (diff) |
refactor material
-rw-r--r-- | src/camera.rs | 8 | ||||
-rw-r--r-- | src/common.rs | 40 | ||||
-rw-r--r-- | src/main.rs | 15 | ||||
-rw-r--r-- | src/material.rs | 18 | ||||
-rw-r--r-- | src/object.rs | 22 |
5 files changed, 69 insertions, 34 deletions
diff --git a/src/camera.rs b/src/camera.rs index 4f2469f..1f211de 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -86,18 +86,12 @@ impl Camera { let mut rec = HitRecord::default(); 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 material = Material::new( - rec.color.clone(), - rec.material.clone(), - rec.fuzz - ); let mut scattered: Ray = Ray { origin: Vec3::random_unit(), direction: Vec3::random_unit(), }; let mut attenuation: Color = Color::new(0.0, 0.0, 0.0); - if material.scatter(ray, &rec, &mut attenuation, &mut scattered) { + if rec.material.scatter(ray, &rec, &mut attenuation, &mut scattered) { return attenuation.elem_prod(&self.ray_color(&mut scattered, &world, depth - 1)); } return Color::new(0.0, 0.0, 0.0); diff --git a/src/common.rs b/src/common.rs index 918c59c..120d8b4 100644 --- a/src/common.rs +++ b/src/common.rs @@ -25,11 +25,51 @@ pub struct Color { pub b: f32, } +pub enum ColorName { + Black, + White, + Red, + Lime, + Blue, + Yellow, + Cyan, + Magenta, + Silver, + Gray, + Maroon, + Olive, + Green, + Purple, + Teal, + Navy, +} + impl Color { pub fn new(r: f32, g: f32, b: f32) -> Self { Self { r, g, b } } + pub fn from_name(name: ColorName) -> Self { + match name { + ColorName::Black => { Self::new(0.0, 0.0, 0.0) } + ColorName::White => { Self::new(1.0, 1.0, 1.0) } + ColorName::Red => { Self::new(1.0, 0.0, 0.0) } + ColorName::Lime => { Self::new(0.0, 1.0, 0.0) } + ColorName::Blue => { Self::new(0.0, 0.0, 1.0) } + ColorName::Yellow => { Self::new(1.0, 1.0, 0.0) } + ColorName::Cyan => { Self::new(0.0, 1.0, 1.0) } + ColorName::Magenta => { Self::new(1.0, 0.0, 1.0) } + ColorName::Silver => { Self::new(0.75, 0.75, 0.75) } + ColorName::Gray => { Self::new(0.5, 0.5, 0.5) } + ColorName::Maroon => { Self::new(0.5, 0.0, 0.0) } + ColorName::Olive => { Self::new(0.5, 0.5, 0.0)} + ColorName::Green => { Self::new(0.0, 0.5, 0.0) } + ColorName::Purple => { Self::new(0.5, 0.0, 0.5) } + ColorName::Teal => { Self::new(0.0, 0.5, 0.5) } + ColorName::Navy => { Self::new(0.0, 0.0, 0.5) } + } + } + pub fn mul_scalar(&self, scalar: f32) -> Color { Self { r: self.r * scalar, diff --git a/src/main.rs b/src/main.rs index fa6c194..cc5d6b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ mod interval; mod material; use crate::calculus::calculus::Point3; -use crate::common::*; use crate::camera::Camera; +use crate::common::*; use crate::material::{Material, MaterialType}; use crate::object::{HittableList, Sphere}; use crate::view::{render_viewer, View}; @@ -17,17 +17,22 @@ fn main() { let mut display_buffer: DisplayBuffer = [[Pixel::default(); IMG_WIDTH]; IMG_HEIGHT]; 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)); + world.push( - Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0, MaterialType::Diffuse, Color::new(0.8, 0.8, 0.0), 0.0) + 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, MaterialType::Diffuse, Color::new(0.1, 0.2, 0.5), 0.0) + Sphere::new(Point3::new(0.0, 0.0, -1.2), 0.5, blue) ); world.push( - Sphere::new(Point3::new(-1.0, 0.0, -1.0), 0.5, MaterialType::Metal, Color::new(0.8, 0.8, 0.8), 0.1) + Sphere::new(Point3::new(-1.0, 0.0, -1.0), 0.5, steel) ); world.push( - Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, MaterialType::Metal, Color::new(0.8, 0.6, 0.2), 0.0) + Sphere::new(Point3::new(1.0, 0.0, -1.0), 0.5, gold) ); let camera = Camera::new(); diff --git a/src/material.rs b/src/material.rs index 731eb0c..a654f4d 100644 --- a/src/material.rs +++ b/src/material.rs @@ -5,19 +5,23 @@ use crate::object::HitRecord; #[derive(Clone)] pub enum MaterialType { Diffuse, - Metal, + Metal(f32), // color fuzz } +#[derive(Clone)] pub struct Material { pub material_type: MaterialType, pub albedo: Color, - pub fuzz: f32, } impl Material { - pub fn new(albedo: Color, material_type: MaterialType, fuzz: f32) -> Self { - let fuzz = if fuzz < 1.0 { fuzz } else { 1.0 }; - Self { albedo, material_type, fuzz } + pub fn new(albedo: Color, material_type: MaterialType) -> Self { + let mut material_type = material_type; + if let MaterialType::Metal(fuzz) = material_type { + let fuzz = if fuzz < 1.0 { fuzz } else { fuzz }; + material_type = MaterialType::Metal(fuzz); + } + Self { albedo, material_type } } pub fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { @@ -30,9 +34,9 @@ impl Material { scatter_direction } } - MaterialType::Metal => { + MaterialType::Metal(fuzz) => { let mut reflected = r_in.reflect(&rec.normal); - reflected.unit().add(&Vec3::random_unit().scalar_mul(self.fuzz)) + reflected.unit().add(&Vec3::random_unit().scalar_mul(fuzz)) } }; diff --git a/src/object.rs b/src/object.rs index 2192703..0161d38 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,7 +1,7 @@ use crate::calculus::calculus::{Point3, Ray, Vec3}; use crate::common::Color; use crate::interval::Interval; -use crate::material::MaterialType; +use crate::material::{Material, MaterialType}; #[derive(Clone)] pub struct HitRecord { @@ -9,9 +9,7 @@ pub struct HitRecord { pub normal: Vec3, pub t: f32, pub front_face: bool, - pub material: MaterialType, - pub color: Color, - pub fuzz: f32, + pub material: Material, } impl Default for HitRecord { @@ -21,9 +19,7 @@ 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), - fuzz: 1.0, + material: Material::new(Color::new(1.0, 1.0, 1.0), MaterialType::Diffuse), } } } @@ -42,15 +38,13 @@ pub trait Hittable { pub struct Sphere { center: Point3, radius: f32, - material: MaterialType, - color: Color, - fuzz: f32, + material: Material, } impl Sphere { - pub fn new(center: Vec3, radius: f32, material: MaterialType, color: Color, fuzz: f32) -> Self { + pub fn new(center: Vec3, radius: f32, material: Material) -> Self { let radius = f32::max(0.0, radius); - Self { center, radius, material, color, fuzz } + Self { center, radius, material } } } @@ -82,8 +76,6 @@ impl Hittable for Sphere { .scalar_mul(1.0 / self.radius); rec.set_face_normal(r, outward_normal); rec.material = self.material.clone(); - rec.color = self.color.clone(); - rec.fuzz = self.fuzz; true } @@ -105,7 +97,7 @@ impl HittableList { impl Hittable for HittableList { fn hit(&self, r: &Ray, ray_t: Interval, rec: &mut HitRecord) -> bool { - let mut temp_rec = HitRecord::default(); + let mut temp_rec = rec.clone(); let mut hit_anything = false; let mut closest_so_far = ray_t.max; |