diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index 16caa7b..607591d 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -3,7 +3,9 @@ extern crate rtiow; #[macro_use] extern crate structopt; +use std::fmt; use std::path::PathBuf; +use std::str; use std::time::Instant; use rand::Rng; @@ -91,66 +93,21 @@ fn random_scene() -> Vec> { objects } -fn build_scene(opt: &Opt) -> Scene { - let (camera, world) = if BOOK_COVER { - let lookfrom = Vec3::new(13., 2., 3.); - let lookat = Vec3::new(0., 0., 0.); - let dist_to_focus = 10.; - let aperture = 0.1; - let cam = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 20., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - ); - let world = HitableList::new(random_scene()); - (cam, world) - } else { - let lookfrom = Vec3::new(3., 3., 2.); - let lookat = Vec3::new(0., 0., -1.); - let dist_to_focus = (lookfrom - lookat).length(); - let aperture = 2.; - let cam = Camera::new( - lookfrom, - lookat, - Vec3::new(0., 1., 0.), - 20., - opt.width as f32 / opt.height as f32, - aperture, - dist_to_focus, - ); - let world = 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.))), - )), - 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(Sphere::new( - Vec3::new(-1., 0., -1.), - 0.5, - Box::new(Dielectric::new(1.5)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - -0.45, - Box::new(Dielectric::new(1.5)), - )), - ]); - (cam, world) - }; +fn build_scene_book(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 camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 20., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + ); + let world = HitableList::new(random_scene()); Scene { camera, world, @@ -160,8 +117,84 @@ fn build_scene(opt: &Opt) -> Scene { } } +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 camera = Camera::new( + lookfrom, + lookat, + Vec3::new(0., 1., 0.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + ); + let world = 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.))), + )), + 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(Sphere::new( + Vec3::new(-1., 0., -1.), + 0.5, + Box::new(Dielectric::new(1.5)), + )), + Box::new(Sphere::new( + Vec3::new(-1., 0., -1.), + -0.45, + Box::new(Dielectric::new(1.5)), + )), + ]); + Scene { + camera, + world, + subsamples: opt.subsamples, + width: opt.width, + height: opt.height, + } +} + +#[derive(Debug)] +pub enum Model { + Book, + Tutorial, +} + +#[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), + "tutorial" => Ok(Model::Tutorial), + _ => Err(ModelParseError(s.to_owned())), + } + } +} + #[derive(Debug, StructOpt)] -#[structopt(name = "tracert", about = "An experimental ray tracer.")] +#[structopt(name = "tracer", about = "An experimental ray tracer.")] pub struct Opt { /// Image width #[structopt(short = "w", long = "width", default_value = "1280")] @@ -172,6 +205,8 @@ pub struct Opt { /// 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))] @@ -181,7 +216,10 @@ pub struct Opt { fn main() -> Result<(), std::io::Error> { let start = Instant::now(); let opt = Opt::from_args(); - let scene = build_scene(&opt); + let scene = match opt.model { + Model::Book => build_scene_book(&opt), + Model::Tutorial => build_scene_tutorial(&opt), + }; let res = render(scene, &opt.output); let runtime = start.elapsed(); eprintln!(