summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-02 16:56:59 +0700
committerRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-02 16:56:59 +0700
commit93b24b9d01f806cf69ecee86fada9e5b9bf06182 (patch)
treec4c941acdeced6cb5b9cc51eedabc994ceda0b38
parentd618968b9577cbaf6306f42157be19bd2a6a6aa0 (diff)
material
-rw-r--r--src/calculus.rs18
-rw-r--r--src/camera.rs22
-rw-r--r--src/main.rs10
-rw-r--r--src/material.rs41
-rw-r--r--src/object.rs14
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
}