use nalgebra::{RealField, Vector3}; use super::colour::{ColourRgbF, NamedColour}; use std::fmt::Debug; pub trait Material: Debug { fn bsdf<'a>( &'a self, ) -> Box, Vector3, ColourRgbF) -> ColourRgbF + 'a>; } #[derive(Debug)] pub struct LambertianMaterial { pub colour: ColourRgbF, pub diffuse_strength: T, } impl LambertianMaterial { pub fn new_dummy() -> LambertianMaterial { LambertianMaterial { colour: ColourRgbF::new(T::one(), T::one(), T::one()), diffuse_strength: T::one(), } } } impl Material for LambertianMaterial { fn bsdf<'a>( &'a self, ) -> Box, Vector3, ColourRgbF) -> ColourRgbF + 'a> { Box::new( move |_w_o: Vector3, _w_i: Vector3, colour_in: ColourRgbF| { self.colour * colour_in * self.diffuse_strength }, ) } } #[derive(Debug)] pub struct PhongMaterial { pub colour: ColourRgbF, pub diffuse_strength: T, pub specular_strength: T, pub smoothness: T, } impl Material for PhongMaterial { fn bsdf<'a>( &'a self, ) -> Box, Vector3, ColourRgbF) -> ColourRgbF + 'a> { Box::new( move |w_o: Vector3, w_i: Vector3, colour_in: ColourRgbF| { if w_i.z < T::zero() || w_o.z < T::zero() { ColourRgbF::from_vector3(&Vector3::zeros()) } else { let reflection_vector = Vector3::new(-w_i.x, -w_i.y, w_i.z); self.colour * colour_in * self.diffuse_strength + ColourRgbF::from_named(NamedColour::White) * w_o.dot(&reflection_vector).abs().powf(self.smoothness) * (self.specular_strength / w_i.dot(&Vector3::z_axis())) } }, ) } }