use std; use rand::{self, Rng}; use crate::{ aabb::AABB, hitable::{Hit, HitRecord}, material::Isotropic, ray::Ray, texture::Texture, vec3::Vec3, }; #[derive(Debug)] pub struct ConstantMedium where H: Hit, T: Texture, { density: f32, material: Isotropic, hitable: H, } impl ConstantMedium where H: Hit, T: Texture, { pub fn new(hitable: H, density: f32, texture: T) -> ConstantMedium where T: Texture, { ConstantMedium { density, material: Isotropic::new(texture), hitable, } } } impl Hit for ConstantMedium where H: Hit, T: Texture, { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let mut rng = rand::thread_rng(); if let Some(mut rec1) = self.hitable.hit(r, std::f32::MIN, std::f32::MAX) { if let Some(mut rec2) = self.hitable.hit(r, rec1.t + 0.001, std::f32::MAX) { if rec1.t < t_min { rec1.t = t_min; } if rec2.t > t_max { rec2.t = t_max; } if rec1.t >= rec2.t { return None; } if rec1.t < 0. { rec1.t = 0.; } let distance_inside_boundary = (rec2.t - rec1.t) * r.direction.length(); let hit_distance: f32 = -(1. / self.density) * rng.gen::().ln(); if hit_distance < distance_inside_boundary { let t = rec1.t + hit_distance / r.direction.length(); let normal = Vec3::new(rng.gen(), rng.gen(), rng.gen()).unit_vector(); return Some(HitRecord { t, p: r.point_at_parameter(t), normal, material: &self.material, uv: (0., 0.), }); } } } None } fn bounding_box(&self, t_min: f32, t_max: f32) -> Option { self.hitable.bounding_box(t_min, t_max) } }