From 57ccefbcdc55d8980a12cb0739081d69bee2c9ee Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Tue, 18 Sep 2018 18:57:20 -0700 Subject: [PATCH] Move scene building to its own set of submodules. --- rtiow/src/bin/tracer.rs | 340 +---------------------------------- rtiow/src/lib.rs | 3 + rtiow/src/renderer.rs | 55 ++++++ rtiow/src/scenes/book.rs | 118 ++++++++++++ rtiow/src/scenes/bvh.rs | 68 +++++++ rtiow/src/scenes/cube.rs | 53 ++++++ rtiow/src/scenes/mod.rs | 4 + rtiow/src/scenes/tutorial.rs | 62 +++++++ 8 files changed, 371 insertions(+), 332 deletions(-) create mode 100644 rtiow/src/scenes/book.rs create mode 100644 rtiow/src/scenes/bvh.rs create mode 100644 rtiow/src/scenes/cube.rs create mode 100644 rtiow/src/scenes/mod.rs create mode 100644 rtiow/src/scenes/tutorial.rs diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index 6b2fc3f..31dd70a 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -3,340 +3,16 @@ extern crate log; extern crate rand; extern crate rtiow; extern crate stderrlog; -#[macro_use] extern crate structopt; -use std::fmt; -use std::path::PathBuf; -use std::str; use std::time::Instant; -use rand::Rng; use structopt::StructOpt; -use rtiow::bvh::BVH; -use rtiow::camera::Camera; -use rtiow::cube::Cube; -use rtiow::hitable::Hit; -use rtiow::hitable_list::HitableList; -use rtiow::material::Dielectric; -use rtiow::material::Lambertian; -use rtiow::material::Metal; -use rtiow::moving_sphere::MovingSphere; use rtiow::renderer::render; -use rtiow::renderer::Scene; -use rtiow::sphere::Sphere; -use rtiow::vec3::Vec3; - -fn random_scene() -> Vec> { - let mut rng = rand::thread_rng(); - let mut objects: Vec> = vec![Box::new(Sphere::new( - Vec3::new(0., -1000., 0.), - 1000., - Box::new(Lambertian::new(Vec3::new(0.5, 0.5, 0.5))), - ))]; - let mut random = || rng.gen_range::(0., 1.); - - for a in -11..11 { - for b in -11..11 { - let choose_mat = random(); - let center = Vec3::new(a as f32 + 0.9 * random(), 0.2, b as f32 + 0.9 * random()); - if (center - Vec3::new(4., 0.2, 0.)).length() > 0.9 { - let sphere = if choose_mat < 0.8 { - // diffuse - Box::new(Sphere::new( - center, - 0.2, - Box::new(Lambertian::new(Vec3::new( - random() * random(), - random() * random(), - random() * random(), - ))), - )) - } else if choose_mat < 0.95 { - // metal - Box::new(Sphere::new( - center, - 0.2, - Box::new(Metal::new( - Vec3::new( - 0.5 * (1. + random()), - 0.5 * (1. + random()), - 0.5 * (1. + random()), - ), - 0.5 * random(), - )), - )) - } else { - // glass - Box::new(Sphere::new(center, 0.2, Box::new(Dielectric::new(1.5)))) - }; - objects.push(sphere); - }; - } - } - - let more: Vec> = vec![ - Box::new(Sphere::new( - Vec3::new(0., 1., 0.), - 1.0, - Box::new(Dielectric::new(1.5)), - )), - Box::new(Sphere::new( - Vec3::new(-4., 1., 0.), - 1.0, - Box::new(Lambertian::new(Vec3::new(0.4, 0.2, 0.1))), - )), - Box::new(Sphere::new( - Vec3::new(4., 1., 0.), - 1.0, - Box::new(Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0)), - )), - ]; - objects.extend(more); - objects -} - -fn build_scene_book(bvh: bool, opt: &Opt) -> Scene { - let lookfrom = Vec3::new(13., 2., 3.); - let lookat = Vec3::new(0., 0., 0.); - let dist_to_focus = 10.; - let aperture = 0.1; - let time_min = 0.; - let time_max = 1.; - let camera = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 20., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - time_min, - time_max, - ); - let world: Box; - if bvh { - let b = BVH::new(random_scene(), time_min, time_max); - trace!(target: "bvh", "World {}", b); - world = Box::new(b); - } else { - world = Box::new(HitableList::new(random_scene())); - } - Scene { - camera, - world, - subsamples: opt.subsamples, - width: opt.width, - height: opt.height, - } -} - -fn build_scene_bvh(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(3., 3., 2.); - let lookat = Vec3::new(0., 0., -1.); - let dist_to_focus = (lookfrom - lookat).length(); - let aperture = 0.1; - let time_min = 0.; - let time_max = 1.; - let camera = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 45., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - time_min, - time_max, - ); - let b = BVH::new( - vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), - )), - Box::new(Sphere::new( - Vec3::new(1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), - )), - Box::new(MovingSphere::new( - Vec3::new(-1., 0., -1.25), - Vec3::new(-1., 0., -0.75), - 0.5, - time_min, - time_max, - Box::new(Lambertian::new(Vec3::new(0.2, 0.8, 0.2))), - )), - ], - time_min, - time_max, - ); - trace!(target: "bvh", "World {}", b); - let world: Box = Box::new(b); - Scene { - camera, - world, - subsamples: opt.subsamples, - width: opt.width, - height: opt.height, - } -} - -fn build_scene_tutorial(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(3., 3., 2.); - let lookat = Vec3::new(0., 0., -1.); - let dist_to_focus = (lookfrom - lookat).length(); - let aperture = 0.1; - let time_min = 0.; - let time_max = 1.; - let camera = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 45., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - time_min, - time_max, - ); - let world: Box = Box::new(HitableList::new(vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), - )), - Box::new(Sphere::new( - Vec3::new(1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), - )), - Box::new(MovingSphere::new( - Vec3::new(-1., 0., -1.25), - Vec3::new(-1., 0., -0.75), - 0.5, - 0., - 1., - Box::new(Lambertian::new(Vec3::new(0.2, 0.8, 0.2))), - )), - ])); - Scene { - camera, - world, - subsamples: opt.subsamples, - width: opt.width, - height: opt.height, - } -} - -fn build_scene_cube(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(3., 3., 2.); - let lookat = Vec3::new(0., 0., 0.); - let dist_to_focus = (lookfrom - lookat).length(); - let aperture = 0.1; - let time_min = 0.; - let time_max = 1.; - let camera = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 45., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - time_min, - time_max, - ); - let world: Box = Box::new(HitableList::new(vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), - )), - Box::new(Cube::new( - Vec3::new(0., 0., 0.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.5, 0.2, 0.1))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), - )), - ])); - Scene { - camera, - world, - subsamples: opt.subsamples, - width: opt.width, - height: opt.height, - } -} - -#[derive(Debug)] -pub enum Model { - Book, - BookBVH, - Tutorial, - Cube, - BVH, -} - -#[derive(Debug)] -pub struct ModelParseError(String); - -impl fmt::Display for ModelParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unknown model enum type '{}'", self.0) - } -} - -impl str::FromStr for Model { - type Err = ModelParseError; - fn from_str(s: &str) -> std::result::Result { - match s { - "book" => Ok(Model::Book), - "book_bvh" => Ok(Model::BookBVH), - "tutorial" => Ok(Model::Tutorial), - "cube" => Ok(Model::Cube), - "bvh" => Ok(Model::BVH), - _ => Err(ModelParseError(s.to_owned())), - } - } -} - -#[derive(Debug, StructOpt)] -#[structopt(name = "tracer", about = "An experimental ray tracer.")] -pub struct Opt { - /// Image width - #[structopt(short = "w", long = "width", default_value = "1280")] - pub width: usize, - /// Image height - #[structopt(short = "h", long = "height", default_value = "720")] - pub height: usize, - /// Sub-samples per pixel - #[structopt(short = "s", long = "subsample", default_value = "10")] - pub subsamples: usize, - #[structopt(long = "model")] - pub model: Model, - - /// Output directory - #[structopt(parse(from_os_str))] - pub output: PathBuf, -} +use rtiow::renderer::Model; +use rtiow::renderer::Opt; +use rtiow::scenes; fn main() -> Result<(), std::io::Error> { stderrlog::new() @@ -347,11 +23,11 @@ fn main() -> Result<(), std::io::Error> { let start = Instant::now(); let opt = Opt::from_args(); let scene = match opt.model { - Model::Book => build_scene_book(false, &opt), - Model::BookBVH => build_scene_book(true, &opt), - Model::Cube => build_scene_cube(&opt), - Model::Tutorial => build_scene_tutorial(&opt), - Model::BVH => build_scene_bvh(&opt), + Model::Book => scenes::book::new(false, &opt), + Model::BookBVH => scenes::book::new(true, &opt), + Model::Cube => scenes::cube::new(&opt), + Model::Tutorial => scenes::tutorial::new(&opt), + Model::BVH => scenes::bvh::new(&opt), }; let res = render(scene, &opt.output); let runtime = start.elapsed(); diff --git a/rtiow/src/lib.rs b/rtiow/src/lib.rs index 8826897..9fc0b7f 100644 --- a/rtiow/src/lib.rs +++ b/rtiow/src/lib.rs @@ -8,6 +8,7 @@ pub mod material; pub mod moving_sphere; pub mod ray; pub mod renderer; +pub mod scenes; pub mod sphere; pub mod vec3; @@ -18,3 +19,5 @@ extern crate log; extern crate num_cpus; extern crate rand; extern crate rayon; +#[macro_use] +extern crate structopt; diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index 11b1422..b9a3c92 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -1,5 +1,8 @@ use std; +use std::fmt; use std::path::Path; +use std::path::PathBuf; +use std::str; use std::sync; use std::thread; @@ -15,6 +18,58 @@ use hitable::Hit; use ray::Ray; use vec3::Vec3; +#[derive(Debug)] +pub enum Model { + Book, + BookBVH, + Tutorial, + Cube, + BVH, +} + +#[derive(Debug)] +pub struct ModelParseError(String); + +impl fmt::Display for ModelParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "unknown model enum type '{}'", self.0) + } +} + +impl str::FromStr for Model { + type Err = ModelParseError; + fn from_str(s: &str) -> std::result::Result { + match s { + "book" => Ok(Model::Book), + "book_bvh" => Ok(Model::BookBVH), + "tutorial" => Ok(Model::Tutorial), + "cube" => Ok(Model::Cube), + "bvh" => Ok(Model::BVH), + _ => Err(ModelParseError(s.to_owned())), + } + } +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "tracer", about = "An experimental ray tracer.")] +pub struct Opt { + /// Image width + #[structopt(short = "w", long = "width", default_value = "1280")] + pub width: usize, + /// Image height + #[structopt(short = "h", long = "height", default_value = "720")] + pub height: usize, + /// Sub-samples per pixel + #[structopt(short = "s", long = "subsample", default_value = "10")] + pub subsamples: usize, + #[structopt(long = "model")] + pub model: Model, + + /// Output directory + #[structopt(parse(from_os_str))] + pub output: PathBuf, +} + pub struct Scene { pub world: Box, pub camera: Camera, diff --git a/rtiow/src/scenes/book.rs b/rtiow/src/scenes/book.rs new file mode 100644 index 0000000..df7f9f8 --- /dev/null +++ b/rtiow/src/scenes/book.rs @@ -0,0 +1,118 @@ +use rand; +use rand::Rng; + +use bvh::BVH; +use camera::Camera; +use hitable::Hit; +use hitable_list::HitableList; +use material::Dielectric; +use material::Lambertian; +use material::Metal; +use renderer::Opt; +use renderer::Scene; +use sphere::Sphere; +use vec3::Vec3; + +pub fn new(bvh: bool, opt: &Opt) -> Scene { + let lookfrom = Vec3::new(13., 2., 3.); + let lookat = Vec3::new(0., 0., 0.); + let dist_to_focus = 10.; + let aperture = 0.1; + let time_min = 0.; + let time_max = 1.; + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 20., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let world: Box; + if bvh { + let b = BVH::new(random_scene(), time_min, time_max); + trace!(target: "bvh", "World {}", b); + world = Box::new(b); + } else { + world = Box::new(HitableList::new(random_scene())); + } + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +} + +fn random_scene() -> Vec> { + let mut rng = rand::thread_rng(); + let mut objects: Vec> = vec![Box::new(Sphere::new( + Vec3::new(0., -1000., 0.), + 1000., + Box::new(Lambertian::new(Vec3::new(0.5, 0.5, 0.5))), + ))]; + let mut random = || rng.gen_range::(0., 1.); + + for a in -11..11 { + for b in -11..11 { + let choose_mat = random(); + let center = Vec3::new(a as f32 + 0.9 * random(), 0.2, b as f32 + 0.9 * random()); + if (center - Vec3::new(4., 0.2, 0.)).length() > 0.9 { + let sphere = if choose_mat < 0.8 { + // diffuse + Box::new(Sphere::new( + center, + 0.2, + Box::new(Lambertian::new(Vec3::new( + random() * random(), + random() * random(), + random() * random(), + ))), + )) + } else if choose_mat < 0.95 { + // metal + Box::new(Sphere::new( + center, + 0.2, + Box::new(Metal::new( + Vec3::new( + 0.5 * (1. + random()), + 0.5 * (1. + random()), + 0.5 * (1. + random()), + ), + 0.5 * random(), + )), + )) + } else { + // glass + Box::new(Sphere::new(center, 0.2, Box::new(Dielectric::new(1.5)))) + }; + objects.push(sphere); + }; + } + } + + let more: Vec> = vec![ + Box::new(Sphere::new( + Vec3::new(0., 1., 0.), + 1.0, + Box::new(Dielectric::new(1.5)), + )), + Box::new(Sphere::new( + Vec3::new(-4., 1., 0.), + 1.0, + Box::new(Lambertian::new(Vec3::new(0.4, 0.2, 0.1))), + )), + Box::new(Sphere::new( + Vec3::new(4., 1., 0.), + 1.0, + Box::new(Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0)), + )), + ]; + objects.extend(more); + objects +} diff --git a/rtiow/src/scenes/bvh.rs b/rtiow/src/scenes/bvh.rs new file mode 100644 index 0000000..dd86cc6 --- /dev/null +++ b/rtiow/src/scenes/bvh.rs @@ -0,0 +1,68 @@ +use bvh::BVH; +use camera::Camera; +use hitable::Hit; +use material::Lambertian; +use material::Metal; +use moving_sphere::MovingSphere; +use renderer::Opt; +use renderer::Scene; +use sphere::Sphere; +use vec3::Vec3; + +pub fn new(opt: &Opt) -> Scene { + let lookfrom = Vec3::new(3., 3., 2.); + let lookat = Vec3::new(0., 0., -1.); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 0.1; + let time_min = 0.; + let time_max = 1.; + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let b = BVH::new( + vec![ + Box::new(Sphere::new( + Vec3::new(0., 0., -1.), + 0.5, + Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), + )), + Box::new(Sphere::new( + Vec3::new(0., -100.5, -1.), + 100., + Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), + )), + Box::new(Sphere::new( + Vec3::new(1., 0., -1.), + 0.5, + Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), + )), + Box::new(MovingSphere::new( + Vec3::new(-1., 0., -1.25), + Vec3::new(-1., 0., -0.75), + 0.5, + time_min, + time_max, + Box::new(Lambertian::new(Vec3::new(0.2, 0.8, 0.2))), + )), + ], + time_min, + time_max, + ); + trace!(target: "bvh", "World {}", b); + let world: Box = Box::new(b); + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +} diff --git a/rtiow/src/scenes/cube.rs b/rtiow/src/scenes/cube.rs new file mode 100644 index 0000000..d9d25ff --- /dev/null +++ b/rtiow/src/scenes/cube.rs @@ -0,0 +1,53 @@ +use camera::Camera; +use cube::Cube; +use hitable::Hit; +use hitable_list::HitableList; +use material::Lambertian; +use renderer::Opt; +use renderer::Scene; +use sphere::Sphere; +use vec3::Vec3; + +pub fn new(opt: &Opt) -> Scene { + let lookfrom = Vec3::new(3., 3., 2.); + let lookat = Vec3::new(0., 0., 0.); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 0.1; + let time_min = 0.; + let time_max = 1.; + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let world: Box = Box::new(HitableList::new(vec![ + Box::new(Sphere::new( + Vec3::new(0., 0., -1.), + 0.5, + Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), + )), + Box::new(Cube::new( + Vec3::new(0., 0., 0.), + 0.5, + Box::new(Lambertian::new(Vec3::new(0.5, 0.2, 0.1))), + )), + Box::new(Sphere::new( + Vec3::new(0., -100.5, -1.), + 100., + Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), + )), + ])); + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +} diff --git a/rtiow/src/scenes/mod.rs b/rtiow/src/scenes/mod.rs new file mode 100644 index 0000000..989a595 --- /dev/null +++ b/rtiow/src/scenes/mod.rs @@ -0,0 +1,4 @@ +pub mod book; +pub mod bvh; +pub mod cube; +pub mod tutorial; diff --git a/rtiow/src/scenes/tutorial.rs b/rtiow/src/scenes/tutorial.rs new file mode 100644 index 0000000..e4ebcc7 --- /dev/null +++ b/rtiow/src/scenes/tutorial.rs @@ -0,0 +1,62 @@ +use camera::Camera; +use hitable::Hit; +use hitable_list::HitableList; +use material::Lambertian; +use material::Metal; +use moving_sphere::MovingSphere; +use renderer::Opt; +use renderer::Scene; +use sphere::Sphere; +use vec3::Vec3; + +pub fn new(opt: &Opt) -> Scene { + let lookfrom = Vec3::new(3., 3., 2.); + let lookat = Vec3::new(0., 0., -1.); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 0.1; + let time_min = 0.; + let time_max = 1.; + let camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let world: Box = Box::new(HitableList::new(vec![ + Box::new(Sphere::new( + Vec3::new(0., 0., -1.), + 0.5, + Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), + )), + Box::new(Sphere::new( + Vec3::new(0., -100.5, -1.), + 100., + Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.8))), + )), + Box::new(Sphere::new( + Vec3::new(1., 0., -1.), + 0.5, + Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), + )), + Box::new(MovingSphere::new( + Vec3::new(-1., 0., -1.25), + Vec3::new(-1., 0., -0.75), + 0.5, + 0., + 1., + Box::new(Lambertian::new(Vec3::new(0.2, 0.8, 0.2))), + )), + ])); + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +}