Add ConstantMedium and cornell_smoke scene.
Shows the ability to compute smoke as a wrapper for anything implementing Hit.
This commit is contained in:
parent
36b2fba5b7
commit
6a1e8b2784
83
rtiow/src/constant_medium.rs
Normal file
83
rtiow/src/constant_medium.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub mod bvh;
|
pub mod bvh;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
|
pub mod constant_medium;
|
||||||
pub mod cuboid;
|
pub mod cuboid;
|
||||||
pub mod flip_normals;
|
pub mod flip_normals;
|
||||||
pub mod hitable;
|
pub mod hitable;
|
||||||
|
|||||||
@ -214,3 +214,25 @@ where
|
|||||||
self.emit.value(u, v, p)
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ pub enum Model {
|
|||||||
BVH,
|
BVH,
|
||||||
Test,
|
Test,
|
||||||
CornellBox,
|
CornellBox,
|
||||||
|
CornellSmoke,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
@ -38,6 +39,7 @@ impl Model {
|
|||||||
Model::BVH => scenes::bvh::new(&opt),
|
Model::BVH => scenes::bvh::new(&opt),
|
||||||
Model::Test => scenes::test::new(&opt),
|
Model::Test => scenes::test::new(&opt),
|
||||||
Model::CornellBox => scenes::cornell_box::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),
|
"bvh" => Ok(Model::BVH),
|
||||||
"test" => Ok(Model::Test),
|
"test" => Ok(Model::Test),
|
||||||
"cornell_box" => Ok(Model::CornellBox),
|
"cornell_box" => Ok(Model::CornellBox),
|
||||||
|
"cornell_smoke" => Ok(Model::CornellSmoke),
|
||||||
_ => Err(ModelParseError(s.to_owned())),
|
_ => Err(ModelParseError(s.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,8 +81,9 @@ pub struct Opt {
|
|||||||
/// Sub-samples per pixel
|
/// Sub-samples per pixel
|
||||||
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
||||||
pub subsamples: usize,
|
pub subsamples: usize,
|
||||||
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box"
|
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box",
|
||||||
#[structopt(long = "model", default_value = "book")]
|
/// "cornell_smoke"
|
||||||
|
#[structopt(long = "model", default_value = "cornell_smoke")]
|
||||||
pub model: Model,
|
pub model: Model,
|
||||||
/// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof
|
/// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof
|
||||||
#[structopt(long = "pprof", parse(from_os_str))]
|
#[structopt(long = "pprof", parse(from_os_str))]
|
||||||
|
|||||||
122
rtiow/src/scenes/cornell_smoke.rs
Normal file
122
rtiow/src/scenes/cornell_smoke.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,5 +2,6 @@ pub mod bench;
|
|||||||
pub mod book;
|
pub mod book;
|
||||||
pub mod bvh;
|
pub mod bvh;
|
||||||
pub mod cornell_box;
|
pub mod cornell_box;
|
||||||
|
pub mod cornell_smoke;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod tutorial;
|
pub mod tutorial;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user