Add ConstantMedium and cornell_smoke scene.

Shows the ability to compute smoke as a wrapper for anything implementing Hit.
This commit is contained in:
Bill Thiede 2018-10-04 21:43:05 -07:00
parent 36b2fba5b7
commit 6a1e8b2784
6 changed files with 235 additions and 2 deletions

View File

@ -0,0 +1,83 @@
use std;
use rand;
use rand::Rng;
use aabb::AABB;
use hitable::Hit;
use hitable::HitRecord;
use material::Material;
use ray::Ray;
use vec3::Vec3;
pub struct ConstantMedium<H, M>
where
H: Hit,
M: Material,
{
density: f32,
material: M,
hitable: H,
}
impl<H, M> ConstantMedium<H, M>
where
H: Hit,
M: Material,
{
pub fn new(hitable: H, density: f32, material: M) -> ConstantMedium<H, M> {
ConstantMedium {
density,
material,
hitable,
}
}
}
impl<H, M> Hit for ConstantMedium<H, M>
where
H: Hit,
M: Material,
{
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::<f32>(0., 1.),
rng.gen_range::<f32>(0., 1.),
rng.gen_range::<f32>(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)
}
}

View File

@ -1,6 +1,7 @@
pub mod aabb;
pub mod bvh;
pub mod camera;
pub mod constant_medium;
pub mod cuboid;
pub mod flip_normals;
pub mod hitable;

View File

@ -214,3 +214,25 @@ where
self.emit.value(u, v, p)
}
}
#[cfg(test)]
mod tests {
use super::*;
use texture::ConstantTexture;
#[test]
fn arc_material() {
let white: Arc<Material> =
Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73])));
fn material_fn<M>(m: M)
where
M: Material,
{
let _ = m;
}
material_fn(Arc::clone(&white));
material_fn(Arc::clone(&white));
}
}

View File

@ -27,6 +27,7 @@ pub enum Model {
BVH,
Test,
CornellBox,
CornellSmoke,
}
impl Model {
@ -38,6 +39,7 @@ impl Model {
Model::BVH => scenes::bvh::new(&opt),
Model::Test => scenes::test::new(&opt),
Model::CornellBox => scenes::cornell_box::new(&opt),
Model::CornellSmoke => scenes::cornell_smoke::new(&opt),
}
}
}
@ -61,6 +63,7 @@ impl str::FromStr for Model {
"bvh" => Ok(Model::BVH),
"test" => Ok(Model::Test),
"cornell_box" => Ok(Model::CornellBox),
"cornell_smoke" => Ok(Model::CornellSmoke),
_ => Err(ModelParseError(s.to_owned())),
}
}
@ -78,8 +81,9 @@ pub struct Opt {
/// Sub-samples per pixel
#[structopt(short = "s", long = "subsample", default_value = "8")]
pub subsamples: usize,
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box"
#[structopt(long = "model", default_value = "book")]
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box",
/// "cornell_smoke"
#[structopt(long = "model", default_value = "cornell_smoke")]
pub model: Model,
/// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof
#[structopt(long = "pprof", parse(from_os_str))]

View File

@ -0,0 +1,122 @@
use std::sync::Arc;
use camera::Camera;
use constant_medium::ConstantMedium;
use cuboid::Cuboid;
use flip_normals::FlipNormals;
use hitable::Hit;
use hitable_list::HitableList;
use kdtree::KDTree;
use material::DiffuseLight;
use material::Lambertian;
use material::Material;
use rect::XYRect;
use rect::XZRect;
use rect::YZRect;
use renderer::Opt;
use renderer::Scene;
use rotate::RotateY;
use texture::ConstantTexture;
use translate::Translate;
use vec3::Vec3;
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(278., 278., -800.);
let lookat = Vec3::new(278., 278., 0.);
let dist_to_focus = 10.0;
let aperture = 0.0;
let time_min = 0.;
let time_max = 1.;
let camera = Camera::new(
lookfrom,
lookat,
Vec3::new(0., 1., 0.),
40.,
opt.width as f32 / opt.height as f32,
aperture,
dist_to_focus,
time_min,
time_max,
);
let red = Lambertian::new(ConstantTexture::new([0.65, 0.05, 0.05]));
let white: Arc<Material> = Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73])));
let green = Lambertian::new(ConstantTexture::new([0.12, 0.45, 0.15]));
let light = DiffuseLight::new(ConstantTexture::new([7., 7., 7.]));
let objects: Vec<Box<Hit>> = vec![
// White smoke box on the right
Box::new(ConstantMedium::new(
Translate::new(
RotateY::new(
Cuboid::new(
Vec3::new(0., 0., 0.),
Vec3::new(165., 165., 165.),
Arc::clone(&white),
),
-18.,
),
Vec3::new(130., 0., 65.),
),
0.01,
Lambertian::new(ConstantTexture::new([1., 1., 1.])),
)),
// Black smoke box on the left
Box::new(ConstantMedium::new(
Translate::new(
RotateY::new(
Cuboid::new(
Vec3::new(0., 0., 0.),
Vec3::new(165., 330., 165.),
Arc::clone(&white),
),
15.,
),
Vec3::new(265., 0., 295.),
),
0.01,
Lambertian::new(ConstantTexture::new([0., 0., 0.])),
)),
// Green wall left
Box::new(FlipNormals::new(YZRect::new(
0., 555., 0., 555., 555., green,
))),
// Red floor right
Box::new(YZRect::new(0., 555., 0., 555., 0., red)),
// Light in ceiling
Box::new(XZRect::new(113., 443., 127., 432., 554., light)),
// Grey ceiling
Box::new(FlipNormals::new(XZRect::new(
0.,
555.,
0.,
555.,
555.,
Arc::clone(&white),
))),
// Grey floor
Box::new(XZRect::new(0., 555., 0., 555., 0., Arc::clone(&white))),
// Grey back wall
Box::new(FlipNormals::new(XYRect::new(
0.,
555.,
0.,
555.,
555.,
Arc::clone(&white),
))),
];
let world: Box<Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max))
} else {
Box::new(HitableList::new(objects))
};
Scene {
camera,
world,
subsamples: opt.subsamples,
width: opt.width,
height: opt.height,
global_illumination: false,
}
}

View File

@ -2,5 +2,6 @@ pub mod bench;
pub mod book;
pub mod bvh;
pub mod cornell_box;
pub mod cornell_smoke;
pub mod test;
pub mod tutorial;