Add scene representing the final image in raytracingthenextweek.

This commit is contained in:
Bill Thiede 2018-10-06 07:26:49 -07:00
parent 7898e7022c
commit bf633756f6
6 changed files with 197 additions and 6 deletions

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use aabb::AABB; use aabb::AABB;
use material::Material; use material::Material;
use ray::Ray; use ray::Ray;
@ -15,3 +17,12 @@ pub trait Hit: Send + Sync {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord>; fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord>;
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB>; fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB>;
} }
impl Hit for Arc<Hit> {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
(**self).hit(r, t_min, t_max)
}
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
(**self).bounding_box(t_min, t_max)
}
}

View File

@ -127,9 +127,15 @@ fn reflect(v: Vec3, n: Vec3) -> Vec3 {
} }
impl Metal { impl Metal {
pub fn new(albedo: Vec3, fuzzy: f32) -> Metal { pub fn new<V>(albedo: V, fuzzy: f32) -> Metal
where
V: Into<Vec3>,
{
let fuzzy = fuzzy.min(1.); let fuzzy = fuzzy.min(1.);
Metal { albedo, fuzzy } Metal {
albedo: albedo.into(),
fuzzy,
}
} }
} }

View File

@ -29,6 +29,7 @@ pub enum Model {
CornellBox, CornellBox,
CornellSmoke, CornellSmoke,
PerlinDebug, PerlinDebug,
Final,
} }
impl Model { impl Model {
@ -42,6 +43,7 @@ impl Model {
Model::CornellBox => scenes::cornell_box::new(&opt), Model::CornellBox => scenes::cornell_box::new(&opt),
Model::CornellSmoke => scenes::cornell_smoke::new(&opt), Model::CornellSmoke => scenes::cornell_smoke::new(&opt),
Model::PerlinDebug => scenes::perlin_debug::new(&opt), Model::PerlinDebug => scenes::perlin_debug::new(&opt),
Model::Final => scenes::final_scene::new(&opt),
} }
} }
} }
@ -67,6 +69,7 @@ impl str::FromStr for Model {
"cornell_box" => Ok(Model::CornellBox), "cornell_box" => Ok(Model::CornellBox),
"cornell_smoke" => Ok(Model::CornellSmoke), "cornell_smoke" => Ok(Model::CornellSmoke),
"perlin_debug" => Ok(Model::PerlinDebug), "perlin_debug" => Ok(Model::PerlinDebug),
"final" => Ok(Model::Final),
_ => Err(ModelParseError(s.to_owned())), _ => Err(ModelParseError(s.to_owned())),
} }
} }
@ -85,8 +88,8 @@ pub struct Opt {
#[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",
/// "cornell_smoke", "perlin_debug" /// "cornell_smoke", "perlin_debug", "final"
#[structopt(long = "model", default_value = "perlin_debug")] #[structopt(long = "model", default_value = "final")]
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))]

View File

@ -0,0 +1,164 @@
use std::sync::Arc;
use image;
use rand;
use rand::Rng;
use camera::Camera;
use constant_medium::ConstantMedium;
use cuboid::Cuboid;
use hitable::Hit;
use hitable_list::HitableList;
use kdtree::KDTree;
use material::Dielectric;
use material::DiffuseLight;
use material::Lambertian;
use material::Material;
use material::Metal;
use moving_sphere::MovingSphere;
use rect::XZRect;
use renderer::Opt;
use renderer::Scene;
use rotate::RotateY;
use sphere::Sphere;
use texture::ConstantTexture;
use texture::ImageTexture;
use texture::NoiseTexture;
use translate::Translate;
use vec3::Vec3;
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(478., 278., -600.);
let lookat = Vec3::new(278., 278., 0.);
let dist_to_focus = 10.;
let aperture = 0.1;
let t_min = 0.;
let t_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,
t_min,
t_max,
);
let nb = 20;
let mut rng = rand::thread_rng();
let mut boxlist: Vec<Box<Hit>> = Vec::with_capacity(10000);
let mut list: Vec<Box<Hit>> = Vec::new();
let white: Arc<Material> = Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73])));
let ground: Arc<Material> = Arc::new(Lambertian::new(ConstantTexture::new([0.48, 0.83, 0.53])));
for i in 0..nb {
for j in 0..nb {
let w = 100.;
let x0 = -1000. + i as f32 * w;
let z0 = -1000. + j as f32 * w;
let y0 = 0.;
let x1 = x0 + w;
let y1 = 100. * (rng.gen_range::<f32>(0., 1.) + 0.01);
let z1 = z0 + w;
boxlist.push(Box::new(Cuboid::new(
Vec3::new(x0, y0, z0),
Vec3::new(x1, y1, z1),
Arc::clone(&ground),
)));
}
}
list.push(Box::new(KDTree::new(boxlist, t_min, t_max)));
let light = DiffuseLight::new(ConstantTexture::new([7., 7., 7.]));
// Light in ceiling
list.push(Box::new(XZRect::new(123., 423., 147., 412., 554., light)));
let center = Vec3::new(400., 400., 200.);
// Moving brownish ball
list.push(Box::new(MovingSphere::new(
center,
center + Vec3::new(30., 0., 0.),
50.,
t_min,
t_max,
Lambertian::new(ConstantTexture::new([0.7, 0.3, 0.1])),
)));
// Glass ball, lower-left corner
list.push(Box::new(Sphere::new(
[260., 150., 45.],
50.,
Dielectric::new(1.5),
)));
// Metal ball lower-right corner
list.push(Box::new(Sphere::new(
[0., 150., 145.],
50.,
Metal::new([0.8, 0.8, 0.9], 10.0),
)));
// Blue smokey glass ball lower-left
let boundary: Arc<Hit> = Arc::new(Sphere::new([360., 150., 145.], 70., Dielectric::new(1.5)));
list.push(Box::new(Arc::clone(&boundary)));
list.push(Box::new(ConstantMedium::new(
Arc::clone(&boundary),
0.2,
ConstantTexture::new([0.2, 0.4, 0.9]),
)));
// General white mist over whole scene
let boundary: Arc<Hit> = Arc::new(Sphere::new([0., 0., 0.], 5000., Dielectric::new(1.5)));
list.push(Box::new(Arc::clone(&boundary)));
list.push(Box::new(ConstantMedium::new(
Arc::clone(&boundary),
0.0001,
ConstantTexture::new([1.0, 1.0, 1.0]),
)));
// Earth sphere
let world_image_bytes = include_bytes!("../../images/world.jpg");
let world = ImageTexture::new(image::load_from_memory(world_image_bytes).unwrap().to_rgb());
list.push(Box::new(Sphere::new(
Vec3::new(400., 200., 400.),
100.,
Lambertian::new(world),
)));
// Perlin noise sphere
let pertext = NoiseTexture::with_scale(0.1);
list.push(Box::new(Sphere::new(
[220., 280., 300.],
80.,
Lambertian::new(pertext),
)));
// White 'cube' made of 1000 spheres
let ns = 1000;
let mut boxlist: Vec<Box<Hit>> = Vec::with_capacity(1000);
for _ in 0..ns {
boxlist.push(Box::new(Sphere::new(
[
165. * rng.gen_range::<f32>(0., 1.),
165. * rng.gen_range::<f32>(0., 1.),
165. * rng.gen_range::<f32>(0., 1.),
],
10.,
Arc::clone(&white),
)));
}
list.push(Box::new(Translate::new(
RotateY::new(KDTree::new(boxlist, t_min, t_max), 15.),
[-100., 270., 395.],
)));
Scene {
camera,
world: Box::new(HitableList::new(list)),
subsamples: opt.subsamples,
width: opt.width,
height: opt.height,
global_illumination: false,
}
}

View File

@ -3,6 +3,7 @@ pub mod book;
pub mod bvh; pub mod bvh;
pub mod cornell_box; pub mod cornell_box;
pub mod cornell_smoke; pub mod cornell_smoke;
pub mod final_scene;
pub mod perlin_debug; pub mod perlin_debug;
pub mod test; pub mod test;
pub mod tutorial; pub mod tutorial;

View File

@ -16,8 +16,14 @@ impl<H> Translate<H>
where where
H: Hit, H: Hit,
{ {
pub fn new(hitable: H, offset: Vec3) -> Translate<H> { pub fn new<V>(hitable: H, offset: V) -> Translate<H>
Translate { hitable, offset } where
V: Into<Vec3>,
{
Translate {
hitable,
offset: offset.into(),
}
} }
} }