use crate::{
HitData,
Material,
Ray, ray,
Vec3, dot, len, reflect, refract
};
pub fn schlick(cosine: f32, refraction_index: f32) -> f32 {
let r0 = (1f32 - refraction_index) / (1f32 + refraction_index);
let r0 = r0 * r0;
r0 + (1f32 - r0) * (1f32 - cosine).powi(5)
}
pub struct Glass {
albedo: Vec3,
pub refraction_index: f32
}
impl Glass {
pub fn new(albedo: Vec3, refraction_index: f32) -> Glass {
Glass {albedo, refraction_index}
}
}
impl Material for Glass {
fn scatter(&self, ray_in: &Ray, hit_data: &HitData) -> (Vec3, Ray) {
let dt = dot!(ray_in.direction, hit_data.normal);
let ray_in_mag = len!(ray_in.direction);
let (normal, n, cosine) = match dt > 0f32 {
true => (
-hit_data.normal,
self.refraction_index,
self.refraction_index * dt / ray_in_mag
),
false => (
hit_data.normal,
self.refraction_index.recip(),
-dt / ray_in_mag
)
};
let attenuation = self.albedo;
let scattered = match refract!(ray_in.direction, normal, n) {
Some(refracted) if rand::random::<f32>() > schlick(cosine, self.refraction_index) => {
ray!(hit_data.point, refracted)
},
_ => {
let reflected = reflect!(ray_in.direction, hit_data.normal);
ray!(hit_data.point, reflected)
}
};
(attenuation, scattered)
}
}