Feat: Materials!

Got the enums to work. This match block is going to be absolutely
massive, but whatever. Current materials are Lambertian and Metal.
This commit is contained in:
2023-06-04 10:31:59 -05:00
parent d1bde8a1a8
commit 7926cd2b13
5 changed files with 125 additions and 28 deletions

View File

@@ -3,9 +3,62 @@ use crate::ray::Ray;
use crate::hittable::HitRecord;
use crate::Vec3;
pub trait Material {
fn scatter(
&self, ray_in: Ray, rec: HitRecord, attenuation: Vec3, scattered: Ray
) -> bool;
use rand::Rng;
use rand::rngs::SmallRng;
use rand::distributions::Uniform;
#[derive(Copy, Clone, Debug)]
pub enum Material{
Lambertian{ albedo: Vec3 },
Metal{ albedo:Vec3 },
}
impl Material {
pub fn scatter(
&self,
ray_in: Ray,
rec: HitRecord,
attenuation: &mut Vec3,
scattered:&mut Ray,
srng: &mut SmallRng,
distrib: Uniform<f32>,
) -> bool {
match self {
Material::Lambertian { albedo } => {
let scatter_dir = rec.normal + Vec3::rand_unit_vector(srng, distrib);
// The compiler might be smart enough to compute this ^^^ just once. In which case,
// I don't need to do this weird dance. Oh well. It'll work.
let scatter_dir = if scatter_dir.near_zero() { // if near zero,
rec.normal // replace with normal
} else {
scatter_dir // else preserve current
};
//TODO: Revisit this out-parameter pattern
// It's a side effect of C++'s obtuse move semantics (and the RTIOW author not
// using them at all)
*scattered = Ray{
orig: rec.p,
dir: scatter_dir
};
*attenuation = *albedo; // deref on both sides? Wacky
return true;
},
Material::Metal { albedo } => {
let reflected = Vec3::reflect(
Vec3::as_unit(&ray_in.dir),
rec.normal
);
*scattered = Ray{
orig: rec.p,
dir: reflected,
};
*attenuation = *albedo;
return Vec3::dot(scattered.dir, rec.normal) > 0.0;
},
_ => return false,
}
}
}