use rand::RngExt; use serde::Deserialize; use crate::{ objects::{hit::Hit, materials::traits::Material}, ray::Ray, vec3::{Colour, Vec3}, }; #[derive(Debug, Deserialize)] pub struct Lambertian { albedo: Colour, prob: f32, } impl Lambertian { pub fn new(albedo: Colour, prob: f32) -> Self { Self { albedo: albedo, prob: prob, } } pub fn rgb(r: f32, g: f32, b: f32, prob: f32) -> Self { Self { albedo: Colour::new(r, g, b), prob: prob, } } } impl Material for Lambertian { fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)> { let mut rng = rand::rng(); if self.prob >= rng.random::() { let mut dir = *hit.n() + Vec3::random_unit(); if dir.near_zero() { dir = *hit.n(); } let scattered = Ray::new(*hit.p(), dir); return Some((scattered, self.albedo)); } return None; } } #[derive(Debug, Deserialize)] pub struct Metal { albedo: Colour, prob: f32, fuzz: f32, } impl Metal { pub fn new(albedo: Colour, prob: f32, fuzz: f32) -> Self { Self { albedo: albedo, prob: prob, fuzz: fuzz, } } pub fn rgb(r: f32, g: f32, b: f32, prob: f32, fuzz: f32) -> Self { Self { albedo: Colour::new(r, g, b), prob: prob, fuzz: fuzz, } } } impl Material for Metal { fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)> { let mut rng = rand::rng(); if self.prob >= rng.random::() { let mut refl = ray.dir().reflect(hit.n()); refl = refl.get_unit() + self.fuzz * Vec3::random_unit(); return Some((Ray::new(*hit.p(), refl), self.albedo)); } return None; } }