raytracers/rtiow/renderer/src/constant_medium.rs
Bill Thiede d9d183b1e5
Some checks failed
continuous-integration/drone/push Build is failing
rtiow: break project into multiple workspaces.
2019-11-09 11:56:33 -08:00

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)
}
}