diff --git a/rtiow/Cargo.lock b/rtiow/Cargo.lock index 30dec14..7945167 100644 --- a/rtiow/Cargo.lock +++ b/rtiow/Cargo.lock @@ -1229,6 +1229,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.2.6" @@ -2434,6 +2440,8 @@ dependencies = [ "serde_json", "stl", "structopt 0.2.18", + "strum", + "strum_macros", "vec3", ] @@ -2462,6 +2470,12 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.12" @@ -2740,7 +2754,7 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro2 0.4.30", "quote 0.6.13", "syn 0.15.44", @@ -2752,13 +2766,35 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro-error", "proc-macro2 1.0.50", "quote 1.0.23", "syn 1.0.107", ] +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.0", + "proc-macro2 1.0.50", + "quote 1.0.23", + "rustversion", + "syn 1.0.107", +] + [[package]] name = "subtle" version = "2.4.1" @@ -3163,6 +3199,7 @@ dependencies = [ "renderer", "stderrlog", "structopt 0.2.18", + "strum", ] [[package]] diff --git a/rtiow/renderer/Cargo.toml b/rtiow/renderer/Cargo.toml index b245290..4f6d702 100644 --- a/rtiow/renderer/Cargo.toml +++ b/rtiow/renderer/Cargo.toml @@ -27,6 +27,8 @@ serde_json = "1.0.91" structopt = "0.2.18" vec3 = {path = "../vec3"} stl = {path = "../../../stl"} +strum = { version = "0.24.1", features = ["derive"] } +strum_macros = "0.24.3" #stl = {git = "https://git-private.z.xinu.tv/wathiede/stl"} [dev-dependencies] diff --git a/rtiow/renderer/src/renderer.rs b/rtiow/renderer/src/renderer.rs index 1226669..c95f357 100644 --- a/rtiow/renderer/src/renderer.rs +++ b/rtiow/renderer/src/renderer.rs @@ -30,8 +30,10 @@ use crate::{ texture::{ConstantTexture, EnvMap}, vec3::Vec3, }; +use strum::{EnumString, EnumVariantNames}; -#[derive(Debug)] +#[derive(Debug, EnumString, EnumVariantNames, strum::Display)] +#[strum(serialize_all = "snake_case")] pub enum Model { BVH, Bench, @@ -46,6 +48,7 @@ pub enum Model { Test, Tron, Tutorial, + Dragon, } impl Model { @@ -56,6 +59,7 @@ impl Model { Model::Book => scenes::book::new(opt), Model::CornellBox => scenes::cornell_box::new(opt), Model::CornellSmoke => scenes::cornell_smoke::new(opt), + Model::Dragon => scenes::dragon::new(opt), Model::Final => scenes::final_scene::new(opt), Model::Mandelbrot => scenes::mandelbrot::new(opt), Model::PerlinDebug => scenes::perlin_debug::new(opt), @@ -77,48 +81,6 @@ impl fmt::Display for ModelParseError { } } -impl str::FromStr for Model { - type Err = ModelParseError; - fn from_str(s: &str) -> std::result::Result { - match s { - "bench" => Ok(Model::Bench), - "book" => Ok(Model::Book), - "bvh" => Ok(Model::BVH), - "cornell_box" => Ok(Model::CornellBox), - "cornell_smoke" => Ok(Model::CornellSmoke), - "final" => Ok(Model::Final), - "mandelbrot" => Ok(Model::Mandelbrot), - "perlin_debug" => Ok(Model::PerlinDebug), - "spheramid" => Ok(Model::Spheramid), - "stltest" => Ok(Model::Stltest), - "test" => Ok(Model::Test), - "tron" => Ok(Model::Tron), - "tutorial" => Ok(Model::Tutorial), - _ => Err(ModelParseError(s.to_owned())), - } - } -} - -impl std::string::ToString for Model { - fn to_string(&self) -> String { - match self { - Model::BVH => "bvh".to_string(), - Model::Bench => "bench".to_string(), - Model::Book => "book".to_string(), - Model::CornellBox => "cornell_box".to_string(), - Model::CornellSmoke => "cornell_smoke".to_string(), - Model::Final => "final".to_string(), - Model::Mandelbrot => "mandelbrot".to_string(), - Model::PerlinDebug => "perlin_debug".to_string(), - Model::Spheramid => "spheramid".to_string(), - Model::Stltest => "stltest".to_string(), - Model::Test => "test".to_string(), - Model::Tron => "tron".to_string(), - Model::Tutorial => "tutorial".to_string(), - } - } -} - #[derive(Debug, StructOpt)] #[structopt(name = "tracer", about = "An experimental ray tracer.")] pub struct Opt { @@ -134,10 +96,9 @@ pub struct Opt { /// Sub-samples per pixel #[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", "final" - #[structopt(long = "model", default_value = "book")] - pub model: Model, + /// Select scene to render. + #[structopt(long = "model")] + pub model: Option, /// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof #[structopt(long = "pprof", parse(from_os_str))] pub pprof: Option, @@ -158,7 +119,7 @@ pub fn opt_hash(opt: &Opt) -> String { opt.height, opt.subsamples, opt.pprof.is_some(), - opt.model.to_string(), + opt.model.as_ref().unwrap().to_string(), opt.use_accel, opt.output.display().to_string().replace('/', "_") ) diff --git a/rtiow/renderer/src/scenes/dragon.rs b/rtiow/renderer/src/scenes/dragon.rs new file mode 100644 index 0000000..eb654db --- /dev/null +++ b/rtiow/renderer/src/scenes/dragon.rs @@ -0,0 +1,119 @@ +use std::{ + io::{BufReader, Cursor}, + sync::Arc, +}; + +use stl::STL; + +use crate::{ + bvh_triangles::BVHTriangles, + camera::Camera, + cuboid::Cuboid, + hitable::Hit, + hitable_list::HitableList, + kdtree::KDTree, + material::{Dielectric, DiffuseLight, Lambertian, Metal}, + rect::{XYRect, XZRect}, + renderer::{Opt, Scene}, + scale::Scale, + sphere::Sphere, + texture::{ConstantTexture, EnvMap}, + vec3::Vec3, +}; + +pub fn new(opt: &Opt) -> Scene { + let lookfrom = Vec3::new(0., 40., -100.); + let lookat = Vec3::new(0., 10., 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.), + 45., + opt.width as f32 / opt.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + let ground_color = if opt.use_accel { + ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)) + } else { + ConstantTexture::new(Vec3::new(0.4, 0.4, 0.4)) + }; + + let stl_cube = STL::parse( + BufReader::new(Cursor::new(include_bytes!( + "../../stls/cube.stl" + //"../../stls/stanford_dragon-lowres.stl" //"../../stls/stanford_dragon.stl" + ))), + false, + ) + .expect("failed to parse cube"); + let light_size = 50.; + let light_height = 200.; + let objects: Vec> = vec![ + // Light from above - white + // Earth sized sphere + Box::new(Sphere::new( + Vec3::new(0., -10000., 0.), + 10000., + Lambertian::new(ground_color), + )), + // Blue sphere + Box::new(Sphere::new( + Vec3::new(0., 20., 40.), + 20., + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))), + )), + Box::new(Sphere::new( + Vec3::new(40., 20., 40.), + 20., + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))), + )), + Box::new(Sphere::new( + Vec3::new(-40., 20., 40.), + 20., + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))), + )), + // STL Mesh + Box::new(Scale::new( + BVHTriangles::new( + &stl_cube, + Dielectric::new(1.5), + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + //Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))), + ), + 1., + //250., + )), + Box::new(Cuboid::new( + [-20., 0., 0.].into(), + [0., 20., 20.].into(), + Arc::new(Dielectric::new(1.5)), + )), + ]; + let world: Box = if opt.use_accel { + Box::new(KDTree::new(objects, time_min, time_max)) + } else { + Box::new(HitableList::new(objects)) + }; + let skybox_bytes = include_bytes!("../../images/envmap.jpg"); + let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb(); + Scene { + camera, + world, + subsamples: opt.subsamples, + num_threads: opt.num_threads, + width: opt.width, + height: opt.height, + global_illumination: true, + env_map: Some(EnvMap::new(skybox)), + ..Default::default() + } +} diff --git a/rtiow/renderer/src/scenes/mod.rs b/rtiow/renderer/src/scenes/mod.rs index 1d71f34..37bf622 100644 --- a/rtiow/renderer/src/scenes/mod.rs +++ b/rtiow/renderer/src/scenes/mod.rs @@ -3,6 +3,7 @@ pub mod book; pub mod bvh; pub mod cornell_box; pub mod cornell_smoke; +pub mod dragon; pub mod final_scene; pub mod mandelbrot; pub mod perlin_debug; diff --git a/rtiow/renderer/src/scenes/stltest.rs b/rtiow/renderer/src/scenes/stltest.rs index c2d2e68..942a22c 100644 --- a/rtiow/renderer/src/scenes/stltest.rs +++ b/rtiow/renderer/src/scenes/stltest.rs @@ -1,23 +1,28 @@ -use std::io::{BufReader, Cursor}; +use std::{ + io::{BufReader, Cursor}, + sync::Arc, +}; + use stl::STL; use crate::{ bvh_triangles::BVHTriangles, camera::Camera, + cuboid::Cuboid, hitable::Hit, hitable_list::HitableList, kdtree::KDTree, - material::{DiffuseLight, Lambertian, Metal}, + material::{Dielectric, DiffuseLight, Lambertian, Metal}, rect::{XYRect, XZRect}, renderer::{Opt, Scene}, scale::Scale, sphere::Sphere, - texture::ConstantTexture, + texture::{ConstantTexture, EnvMap}, vec3::Vec3, }; pub fn new(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(-20., 100., -100.); + let lookfrom = Vec3::new(0., 40., -100.); let lookat = Vec3::new(0., 10., 0.); let dist_to_focus = 10.0; let aperture = 0.0; @@ -41,9 +46,7 @@ pub fn new(opt: &Opt) -> Scene { }; let stl_cube = STL::parse( - BufReader::new(Cursor::new(include_bytes!( - "../../stls/stanford_dragon-lowres.stl" - ))), + BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))), false, ) .expect("failed to parse cube"); @@ -51,65 +54,41 @@ pub fn new(opt: &Opt) -> Scene { let light_height = 200.; let objects: Vec> = vec![ // Light from above - white - Box::new(XZRect::new( - -light_size, - light_size, - -light_size, - light_size, - light_height, - DiffuseLight::new(ConstantTexture::new(Vec3::new(15., 15., 15.))), - )), - // Light from back - green - Box::new(XYRect::new( - -light_size, - light_size, - -light_size, - light_size, - -light_height, - DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 15., 1.))), - )), - // Light from front - blue - Box::new(XYRect::new( - -light_size, - light_size, - -light_size, - light_size, - light_height, - DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 15.))), - )), // Earth sized sphere Box::new(Sphere::new( - Vec3::new(0., -1200., 0.), - 1000., + Vec3::new(0., -10000., 0.), + 10000., Lambertian::new(ground_color), )), - /* // Blue sphere Box::new(Sphere::new( - Vec3::new(-40., 20., 0.), + Vec3::new(0., 20., 40.), 20., - Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))), )), - */ - // Shiny sphere Box::new(Sphere::new( - Vec3::new(40., 20., -40.), + Vec3::new(40., 20., 40.), 20., - Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))), )), Box::new(Sphere::new( Vec3::new(-40., 20., 40.), 20., - Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))), )), // STL Mesh - Box::new(Scale::new( - BVHTriangles::new( - &stl_cube, - Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))), - ), - //1., - 250., + Box::new(BVHTriangles::new( + &stl_cube, + Dielectric::new(1.5), + //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), + //Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))), + )), + Box::new(Cuboid::new( + [-20., 0., 0.].into(), + [0., 20., 20.].into(), + Arc::new(Dielectric::new(1.5)), )), ]; let world: Box = if opt.use_accel { @@ -117,6 +96,8 @@ pub fn new(opt: &Opt) -> Scene { } else { Box::new(HitableList::new(objects)) }; + let skybox_bytes = include_bytes!("../../images/envmap.jpg"); + let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb(); Scene { camera, world, @@ -124,6 +105,8 @@ pub fn new(opt: &Opt) -> Scene { num_threads: opt.num_threads, width: opt.width, height: opt.height, + global_illumination: true, + env_map: Some(EnvMap::new(skybox)), ..Default::default() } } diff --git a/rtiow/renderer/stls/20mm cube.stl b/rtiow/renderer/stls/cube.stl similarity index 100% rename from rtiow/renderer/stls/20mm cube.stl rename to rtiow/renderer/stls/cube.stl diff --git a/rtiow/renderer/stls/stanford_dragon-lowres.stl b/rtiow/renderer/stls/stanford_dragon-lowres.stl new file mode 120000 index 0000000..bd8520a --- /dev/null +++ b/rtiow/renderer/stls/stanford_dragon-lowres.stl @@ -0,0 +1 @@ +/home/wathiede/3dprint/stl/stanford_dragon-lowres.stl \ No newline at end of file diff --git a/rtiow/tracer/Cargo.toml b/rtiow/tracer/Cargo.toml index 259b3ec..d4d5572 100644 --- a/rtiow/tracer/Cargo.toml +++ b/rtiow/tracer/Cargo.toml @@ -11,3 +11,4 @@ log = "0.4.17" renderer = { path = "../renderer" } stderrlog = "0.4.3" structopt = "0.2.18" +strum = "0.24.1" diff --git a/rtiow/tracer/src/main.rs b/rtiow/tracer/src/main.rs index 8f4227b..52a3fcc 100644 --- a/rtiow/tracer/src/main.rs +++ b/rtiow/tracer/src/main.rs @@ -6,7 +6,8 @@ use cpuprofiler::PROFILER; use log::info; use structopt::StructOpt; -use renderer::renderer::{render, Opt}; +use renderer::renderer::{render, Model, Opt}; +use strum::VariantNames; #[cfg(not(feature = "profile"))] struct MockTimer; @@ -41,8 +42,12 @@ fn main() -> Result<(), std::io::Error> { .init() .unwrap(); let opt = Opt::from_args(); + if opt.model.is_none() { + eprintln!("--model should be one of {:?}", Model::VARIANTS); + return Ok(()); + } info!("{:?}", opt); - let scene = opt.model.scene(&opt); + let scene = opt.model.as_ref().unwrap().scene(&opt); fs::create_dir_all(&opt.output)?; if opt.pprof.is_some() && !cfg!(feature = "profile") { panic!("profiling disabled at compile time, but -pprof specified");