diff --git a/rtiow/src/hitable.rs b/rtiow/src/hitable.rs index d07254c..6fa7405 100644 --- a/rtiow/src/hitable.rs +++ b/rtiow/src/hitable.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use aabb::AABB; use material::Material; use ray::Ray; @@ -15,3 +17,12 @@ pub trait Hit: Send + Sync { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option; fn bounding_box(&self, t_min: f32, t_max: f32) -> Option; } + +impl Hit for Arc { + fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { + (**self).hit(r, t_min, t_max) + } + fn bounding_box(&self, t_min: f32, t_max: f32) -> Option { + (**self).bounding_box(t_min, t_max) + } +} diff --git a/rtiow/src/material.rs b/rtiow/src/material.rs index 0a24ded..c20dfca 100644 --- a/rtiow/src/material.rs +++ b/rtiow/src/material.rs @@ -127,9 +127,15 @@ fn reflect(v: Vec3, n: Vec3) -> Vec3 { } impl Metal { - pub fn new(albedo: Vec3, fuzzy: f32) -> Metal { + pub fn new(albedo: V, fuzzy: f32) -> Metal + where + V: Into, + { let fuzzy = fuzzy.min(1.); - Metal { albedo, fuzzy } + Metal { + albedo: albedo.into(), + fuzzy, + } } } diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index d20b689..f2de053 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -29,6 +29,7 @@ pub enum Model { CornellBox, CornellSmoke, PerlinDebug, + Final, } impl Model { @@ -42,6 +43,7 @@ impl Model { Model::CornellBox => scenes::cornell_box::new(&opt), Model::CornellSmoke => scenes::cornell_smoke::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_smoke" => Ok(Model::CornellSmoke), "perlin_debug" => Ok(Model::PerlinDebug), + "final" => Ok(Model::Final), _ => Err(ModelParseError(s.to_owned())), } } @@ -85,8 +88,8 @@ pub struct Opt { #[structopt(short = "s", long = "subsample", default_value = "8")] pub subsamples: usize, /// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box", - /// "cornell_smoke", "perlin_debug" - #[structopt(long = "model", default_value = "perlin_debug")] + /// "cornell_smoke", "perlin_debug", "final" + #[structopt(long = "model", default_value = "final")] pub model: Model, /// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof #[structopt(long = "pprof", parse(from_os_str))] diff --git a/rtiow/src/scenes/final_scene.rs b/rtiow/src/scenes/final_scene.rs new file mode 100644 index 0000000..8143e95 --- /dev/null +++ b/rtiow/src/scenes/final_scene.rs @@ -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> = Vec::with_capacity(10000); + let mut list: Vec> = Vec::new(); + let white: Arc = Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73]))); + let ground: Arc = 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::(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 = 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 = 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> = Vec::with_capacity(1000); + for _ in 0..ns { + boxlist.push(Box::new(Sphere::new( + [ + 165. * rng.gen_range::(0., 1.), + 165. * rng.gen_range::(0., 1.), + 165. * rng.gen_range::(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, + } +} diff --git a/rtiow/src/scenes/mod.rs b/rtiow/src/scenes/mod.rs index ae0cd14..c88a75b 100644 --- a/rtiow/src/scenes/mod.rs +++ b/rtiow/src/scenes/mod.rs @@ -3,6 +3,7 @@ pub mod book; pub mod bvh; pub mod cornell_box; pub mod cornell_smoke; +pub mod final_scene; pub mod perlin_debug; pub mod test; pub mod tutorial; diff --git a/rtiow/src/translate.rs b/rtiow/src/translate.rs index aeb612e..1c3e66c 100644 --- a/rtiow/src/translate.rs +++ b/rtiow/src/translate.rs @@ -16,8 +16,14 @@ impl Translate where H: Hit, { - pub fn new(hitable: H, offset: Vec3) -> Translate { - Translate { hitable, offset } + pub fn new(hitable: H, offset: V) -> Translate + where + V: Into, + { + Translate { + hitable, + offset: offset.into(), + } } }