From 37137ac9ca670b59dfe65287290dfc27a9724600 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Wed, 15 Feb 2023 14:40:25 -0800 Subject: [PATCH] rtiow: add bones of a scene file format based on toml. --- rtiow/renderer/src/camera.rs | 1 + rtiow/renderer/src/lib.rs | 1 + rtiow/renderer/src/parser.rs | 94 +++++++++++++++++++++++++++++ rtiow/renderer/src/renderer.rs | 5 +- rtiow/renderer/src/scenes/dragon.rs | 1 - rtiow/tracer/Cargo.toml | 2 + rtiow/tracer/configs/test.toml | 24 ++++++++ rtiow/tracer/src/main.rs | 32 ++++++++-- 8 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 rtiow/renderer/src/parser.rs create mode 100644 rtiow/tracer/configs/test.toml diff --git a/rtiow/renderer/src/camera.rs b/rtiow/renderer/src/camera.rs index a525b34..e2ab5f5 100644 --- a/rtiow/renderer/src/camera.rs +++ b/rtiow/renderer/src/camera.rs @@ -18,6 +18,7 @@ fn random_in_unit_disk() -> Vec3 { } } +#[derive(Debug)] pub struct Camera { origin: Vec3, lower_left_corner: Vec3, diff --git a/rtiow/renderer/src/lib.rs b/rtiow/renderer/src/lib.rs index fe34e46..28fa34f 100644 --- a/rtiow/renderer/src/lib.rs +++ b/rtiow/renderer/src/lib.rs @@ -16,6 +16,7 @@ pub mod material; pub mod moving_sphere; pub mod noise; pub mod output; +pub mod parser; pub mod ray; pub mod rect; pub mod renderer; diff --git a/rtiow/renderer/src/parser.rs b/rtiow/renderer/src/parser.rs new file mode 100644 index 0000000..2ee4f0f --- /dev/null +++ b/rtiow/renderer/src/parser.rs @@ -0,0 +1,94 @@ +use crate::{ + camera::Camera, + hitable::Hit, + hitable_list::HitableList, + material::Lambertian, + renderer::Scene, + sphere::Sphere, + texture::{EnvMap, Texture}, +}; +use serde::Deserialize; + +use vec3::Vec3; + +#[derive(Debug, Deserialize)] +pub struct Config { + scene: SceneConfig, + camera: CameraConfig, + spheres: Vec, +} + +impl From for Scene { + fn from(c: Config) -> Scene { + let material = Lambertian::new([1., 0., 0.]); + let objects: Vec> = c + .spheres + .iter() + .map(|sc| -> Box { + Box::new(Sphere::new(sc.center, sc.radius, material.clone())) + }) + .collect(); + let world: Box = Box::new(HitableList::new(objects)); + let env_map: Option = None; + + let lookfrom = Vec3::new(0., 80., 80.); + let lookat = Vec3::new(0., 0., 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., + c.scene.width as f32 / c.scene.height as f32, + aperture, + dist_to_focus, + time_min, + time_max, + ); + + let scene = Scene { + world, + camera, + env_map, + subsamples: c.scene.subsamples.unwrap_or(8), + adaptive_subsampling: c.scene.adaptive_subsampling, + num_threads: c.scene.num_threads, + width: c.scene.width, + height: c.scene.height, + global_illumination: c.scene.global_illumination.unwrap_or(true), + }; + dbg!(&scene); + scene + } +} + +#[derive(Debug, Deserialize)] +struct SceneConfig { + subsamples: Option, + adaptive_subsampling: Option, + num_threads: Option, + width: usize, + height: usize, + global_illumination: Option, +} + +#[derive(Debug, Deserialize)] +struct SphereConfig { + center: [f32; 3], + radius: f32, +} + +#[derive(Debug, Deserialize)] +pub struct CameraConfig { + lookfrom: [f32; 3], + lookat: [f32; 3], + fov: f32, + aspect: f32, + aperture: f32, + focus_dist: f32, + time_min: f32, + time_max: f32, +} diff --git a/rtiow/renderer/src/renderer.rs b/rtiow/renderer/src/renderer.rs index adb875a..baf2f81 100644 --- a/rtiow/renderer/src/renderer.rs +++ b/rtiow/renderer/src/renderer.rs @@ -99,6 +99,9 @@ pub struct Opt { /// Select scene to render. #[structopt(long = "model")] pub model: Option, + /// Toml config describing scene. + #[structopt(long = "config")] + pub config: Option, /// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof #[structopt(long = "pprof", parse(from_os_str))] pub pprof: Option, @@ -126,7 +129,7 @@ pub fn opt_hash(opt: &Opt) -> String { } // TODO(wathiede): implement the skips and then the renderer could use json as an input file type. -#[derive(Serialize)] +#[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Scene { #[serde(skip)] diff --git a/rtiow/renderer/src/scenes/dragon.rs b/rtiow/renderer/src/scenes/dragon.rs index 7a2170c..c096ca9 100644 --- a/rtiow/renderer/src/scenes/dragon.rs +++ b/rtiow/renderer/src/scenes/dragon.rs @@ -53,7 +53,6 @@ pub fn new(opt: &Opt) -> Scene { let stl_cube = STL::parse( BufReader::new(Cursor::new(include_bytes!("../../stls/dragon.stl"))), - //BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))), false, ) .expect("failed to parse cube"); diff --git a/rtiow/tracer/Cargo.toml b/rtiow/tracer/Cargo.toml index d4d5572..4a39c27 100644 --- a/rtiow/tracer/Cargo.toml +++ b/rtiow/tracer/Cargo.toml @@ -7,8 +7,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.69" log = "0.4.17" renderer = { path = "../renderer" } stderrlog = "0.4.3" structopt = "0.2.18" strum = "0.24.1" +toml = "0.7.2" diff --git a/rtiow/tracer/configs/test.toml b/rtiow/tracer/configs/test.toml new file mode 100644 index 0000000..0b5ece2 --- /dev/null +++ b/rtiow/tracer/configs/test.toml @@ -0,0 +1,24 @@ +[scene] +width = 768 +height = 768 +subsamples = 1000 + +[camera] +lookfrom = [0.0, 10.0, 0.0] +lookat = [0.0, 0.0, 0.0] +fov = 45.0 +aspect = 1 +aperture = 0.0 +focus_dist = 10.0 +time_min = 0.0 +time_max = 1.0 + +[[spheres]] +center = [0.0, 0.0, 0.0] +radius = 10 +[[spheres]] +center = [30.0, 0.0, 0.0] +radius = 10 +[[spheres]] +center = [-30.0, 0.0, 0.0] +radius = 10 diff --git a/rtiow/tracer/src/main.rs b/rtiow/tracer/src/main.rs index b6e63b9..5ab9542 100644 --- a/rtiow/tracer/src/main.rs +++ b/rtiow/tracer/src/main.rs @@ -1,12 +1,16 @@ #![warn(unused_extern_crates)] use std::{fs, time::Instant}; +use anyhow::Result; #[cfg(feature = "profile")] use cpuprofiler::PROFILER; use log::info; use structopt::StructOpt; -use renderer::renderer::{render, Model, Opt}; +use renderer::{ + parser::Config, + renderer::{render, Model, Opt}, +}; use strum::VariantNames; #[cfg(not(feature = "profile"))] @@ -35,7 +39,7 @@ impl MockProfiler { #[cfg(not(feature = "profile"))] static PROFILER: MockProfiler = MockProfiler {}; -fn main() -> Result<(), std::io::Error> { +fn main() -> Result<()> { let start_time = Instant::now(); stderrlog::new() .verbosity(3) @@ -43,12 +47,28 @@ 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); + if opt.model.is_none() && opt.config.is_none() { + eprintln!( + "--config or --model should be one of {:?}", + Model::VARIANTS + ); + return Ok(()); + } + if opt.model.is_some() && opt.config.is_some() { + eprintln!("only specify one of --config or --model"); return Ok(()); } info!("{:#?}", opt); - let scene = opt.model.as_ref().unwrap().scene(&opt); + let scene = match (&opt.model, &opt.config) { + (Some(model), None) => model.scene(&opt), + (None, Some(config)) => { + let s = std::fs::read_to_string(config)?; + let cfg: Config = toml::from_str(&s)?; + println!("{:#?}", cfg); + cfg.into() + } + _ => unreachable!(), + }; fs::create_dir_all(&opt.output)?; if opt.pprof.is_some() && !cfg!(feature = "profile") { panic!("profiling disabled at compile time, but -pprof specified"); @@ -68,5 +88,5 @@ fn main() -> Result<(), std::io::Error> { let time_diff = Instant::now() - start_time; info!("Total runtime {} seconds", time_diff.as_secs_f32()); - res + Ok(res?) }