89 lines
2.3 KiB
Rust
89 lines
2.3 KiB
Rust
use std;
|
|
|
|
use rand;
|
|
use rand::Rng;
|
|
|
|
use crate::aabb::AABB;
|
|
use crate::hitable::Hit;
|
|
use crate::hitable::HitRecord;
|
|
use crate::material::Isotropic;
|
|
use crate::ray::Ray;
|
|
use crate::texture::Texture;
|
|
use crate::vec3::Vec3;
|
|
|
|
pub struct ConstantMedium<H, T>
|
|
where
|
|
H: Hit,
|
|
T: Texture,
|
|
{
|
|
density: f32,
|
|
material: Isotropic<T>,
|
|
hitable: H,
|
|
}
|
|
|
|
impl<H, T> ConstantMedium<H, T>
|
|
where
|
|
H: Hit,
|
|
T: Texture,
|
|
{
|
|
pub fn new(hitable: H, density: f32, texture: T) -> ConstantMedium<H, T>
|
|
where
|
|
T: Texture,
|
|
{
|
|
ConstantMedium {
|
|
density,
|
|
material: Isotropic::new(texture),
|
|
hitable,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<H, T> Hit for ConstantMedium<H, T>
|
|
where
|
|
H: Hit,
|
|
T: Texture,
|
|
{
|
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
|
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 = -(1. / self.density) * rng.gen_range::<f32>(0., 1.).ln();
|
|
if hit_distance < distance_inside_boundary {
|
|
let t = rec1.t + hit_distance / r.direction.length();
|
|
let normal = Vec3::new(
|
|
rng.gen_range(0., 1.),
|
|
rng.gen_range(0., 1.),
|
|
rng.gen_range(0., 1.),
|
|
)
|
|
.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<AABB> {
|
|
self.hitable.bounding_box(t_min, t_max)
|
|
}
|
|
}
|