89 lines
2.6 KiB
Rust
89 lines
2.6 KiB
Rust
use std::sync::Arc;
|
|
use crate::{Aabb, Color, Material, Ray, Vec3};
|
|
use crate::hittable::{HitRecord, Hittable};
|
|
use crate::isotropic::Isotropic;
|
|
use crate::texture::Texture;
|
|
|
|
/*
|
|
#[derive(Clone, Copy)]
|
|
pub struct HitRecord<'material> {
|
|
pub point: Point3,
|
|
pub normal: Vec3,
|
|
pub t: f64,
|
|
pub u: f64,
|
|
pub v: f64,
|
|
pub front_face: bool,
|
|
pub material: &'material Arc<Material>
|
|
}
|
|
*/
|
|
|
|
pub struct ConstantMedium<H: Hittable> {
|
|
boundary: H,
|
|
phase_function: Arc<Material>,
|
|
neg_inv_density: f64
|
|
}
|
|
|
|
impl<H: Hittable,> ConstantMedium<H> {
|
|
pub fn new(boundary: H, phase_function: Arc<Material>, density: f64) -> Self {
|
|
Self {
|
|
boundary,
|
|
phase_function,
|
|
neg_inv_density: -1.0 / density
|
|
}
|
|
}
|
|
pub fn textured(boundary: H, texture: Arc<dyn Texture>, density: f64) -> Self {
|
|
Self {
|
|
boundary,
|
|
phase_function: Arc::new(Material::Isotropic(Isotropic::from(texture))),
|
|
neg_inv_density: -1.0 / density
|
|
}
|
|
}
|
|
pub fn colored(boundary: H, color: Color, density: f64) -> Self {
|
|
Self {
|
|
boundary,
|
|
phase_function: Arc::new(Material::Isotropic(Isotropic::from(color))),
|
|
neg_inv_density: -1.0 / density
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<H: Hittable>Hittable for ConstantMedium<H>{
|
|
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
|
let rec1 = self.boundary.hit(ray, f64::NEG_INFINITY, f64::INFINITY);
|
|
if rec1.is_none() {
|
|
return None;
|
|
}
|
|
let mut rec1 = rec1.unwrap();
|
|
|
|
let rec2 = self.boundary.hit(ray, rec1.t+0.0001, f64::INFINITY);
|
|
if rec2.is_none() {
|
|
return None;
|
|
}
|
|
let mut rec2 = rec2.unwrap();
|
|
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 < t_min { rec1.t = 0.0; }
|
|
|
|
let ray_length = ray.direction().length();
|
|
let distance_inside_boundary = (rec2.t - rec1.t) * ray_length;
|
|
let hit_distance = self.neg_inv_density * rand::random::<f64>().ln();
|
|
|
|
if hit_distance > distance_inside_boundary { return None; }
|
|
let t = rec1.t + hit_distance / ray_length;
|
|
Some(HitRecord {
|
|
point: ray.at(t),
|
|
normal: Vec3::new(1.0, 0.0, 0.0), // arbitrary
|
|
t,
|
|
u: 0.0,
|
|
v: 0.0,
|
|
front_face: true, // also arbitrary
|
|
material: &self.phase_function
|
|
})
|
|
}
|
|
|
|
fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb> {
|
|
self.boundary.bounding_box(time0, time1)
|
|
}
|
|
}
|