diff --git a/rtiow/renderer/src/parser.rs b/rtiow/renderer/src/parser.rs index ea67f08..fdd346b 100644 --- a/rtiow/renderer/src/parser.rs +++ b/rtiow/renderer/src/parser.rs @@ -4,13 +4,13 @@ use crate::{ cuboid::Cuboid, hitable::Hit, hitable_list::HitableList, - material::Lambertian, + material::{Lambertian, Material, Metal}, renderer::Scene, sphere::Sphere, texture::{EnvMap, Texture}, }; use serde::Deserialize; -use std::{fs::File, io::BufReader, path::PathBuf, sync::Arc}; +use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf, sync::Arc}; use stl::STL; use thiserror::Error; use vec3::Vec3; @@ -19,6 +19,7 @@ use vec3::Vec3; pub struct Config { scene: SceneConfig, camera: CameraConfig, + materials: Vec, hitables: Vec, envmap: Option, } @@ -31,35 +32,59 @@ pub enum ConfigError { STLError(#[from] stl::ParseError), #[error("I/O error")] IOError(#[from] std::io::Error), + #[error("duplication material named '{0}'")] + DuplicateMaterial(String), + #[error("unkown material named '{0}'")] + UnknownMaterial(String), } impl TryFrom for Scene { type Error = ConfigError; fn try_from(c: Config) -> Result { - // TODO(wathiede): make this something that is loaded from the config and referenced by - // name in the object's config. - let material = Lambertian::new([1., 0., 0.]); + let mut materials = HashMap::new(); + for mc in c.materials { + let v: Arc = match mc.material { + Materials::Metal { albedo, fuzzy } => Arc::new(Metal::new(albedo, fuzzy)), + }; + if materials.insert(mc.name.clone(), v).is_some() { + return Err(ConfigError::DuplicateMaterial(mc.name)); + } + } let hitables: Result>, Self::Error> = c .hitables .into_iter() .map(|hc| -> Result, Self::Error> { - match hc { - HitableConfig::Sphere { center, radius } => { - Ok(Box::new(Sphere::new(center, radius, material.clone()))) - } - HitableConfig::Cuboid { min, max } => Ok(Box::new(Cuboid::new( + match hc.hitable { + Hitables::Sphere { center, radius } => Ok(Box::new(Sphere::new( + center, + radius, + Arc::clone( + materials + .get(&hc.material_name) + .ok_or(ConfigError::UnknownMaterial(hc.material_name))?, + ), + ))), + Hitables::Cuboid { min, max } => Ok(Box::new(Cuboid::new( min.into(), max.into(), - Arc::new(material.clone()), + Arc::clone( + materials + .get(&hc.material_name) + .ok_or(ConfigError::UnknownMaterial(hc.material_name))?, + ), ))), - HitableConfig::STL { path, scale } => { + Hitables::STL { path, scale } => { let r = BufReader::new(File::open(path)?); let stl = STL::parse(r, false)?; Ok(Box::new(BVHTriangles::new( &stl, - material.clone(), + Arc::clone( + materials + .get(&hc.material_name) + .ok_or(ConfigError::UnknownMaterial(hc.material_name))?, + ), scale.unwrap_or(1.), ))) } @@ -119,7 +144,15 @@ struct SceneConfig { #[derive(Debug, Deserialize)] #[serde(tag = "type")] -enum HitableConfig { +struct HitableConfig { + material_name: String, + #[serde(flatten)] + hitable: Hitables, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +enum Hitables { #[serde(rename = "sphere")] Sphere { center: [f32; 3], radius: f32 }, #[serde(rename = "cuboid")] @@ -128,12 +161,25 @@ enum HitableConfig { STL { path: PathBuf, scale: Option }, } +#[derive(Debug, Deserialize)] +struct MaterialConfig { + name: String, + #[serde(flatten)] + material: Materials, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +enum Materials { + #[serde(rename = "metal")] + Metal { albedo: [f32; 3], fuzzy: 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, diff --git a/rtiow/renderer/src/renderer.rs b/rtiow/renderer/src/renderer.rs index baf2f81..c2023b8 100644 --- a/rtiow/renderer/src/renderer.rs +++ b/rtiow/renderer/src/renderer.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashMap, fmt, ops::{AddAssign, Range}, path::{Path, PathBuf}, @@ -22,7 +23,7 @@ use crate::{ camera::Camera, hitable::Hit, human, - material::Lambertian, + material::{Lambertian, Material}, output, ray::Ray, scenes, @@ -134,6 +135,8 @@ pub fn opt_hash(opt: &Opt) -> String { pub struct Scene { #[serde(skip)] pub world: Box, + //#[serde(skip)] + //pub materials: HashMap>, #[serde(skip)] pub camera: Camera, pub subsamples: usize, diff --git a/rtiow/renderer/src/scenes/book.rs b/rtiow/renderer/src/scenes/book.rs index 102be65..ff5715d 100644 --- a/rtiow/renderer/src/scenes/book.rs +++ b/rtiow/renderer/src/scenes/book.rs @@ -52,6 +52,7 @@ pub fn new(opt: &Opt) -> Scene { height: opt.height, global_illumination: true, env_map: Some(EnvMap::new(skybox)), + ..Default::default() } } diff --git a/rtiow/renderer/src/scenes/spheramid.rs b/rtiow/renderer/src/scenes/spheramid.rs index 58520fe..befe57c 100644 --- a/rtiow/renderer/src/scenes/spheramid.rs +++ b/rtiow/renderer/src/scenes/spheramid.rs @@ -112,5 +112,6 @@ pub fn new(opt: &Opt) -> Scene { height: opt.height, global_illumination: true, env_map: Some(EnvMap::new(skybox)), + ..Default::default() } } diff --git a/rtiow/tracer/configs/test.toml b/rtiow/tracer/configs/test.toml index 1e8be5a..7bd2925 100644 --- a/rtiow/tracer/configs/test.toml +++ b/rtiow/tracer/configs/test.toml @@ -7,24 +7,43 @@ height = 768 lookfrom = [0.0, 30.0, -100.0] lookat = [0.0, 0.0, 0.0] fov = 45 -aspect = 1 aperture = 0.0 focus_dist = 10.0 time_min = 0.0 time_max = 1.0 +[[materials]] +name = "green" +type = "metal" +albedo = [0, 1, 0] +fuzzy = 1.5 +[[materials]] +name = "blue" +type = "metal" +albedo = [0, 0, 1] +fuzzy = 1.5 +[[materials]] +name = "red" +type = "metal" +albedo = [1, 0, 0] +fuzzy = 1.5 + + [[hitables]] type = "cuboid" min = [-10.0, -10.0, -10.0] max = [10.0, 10.0, 10.0] +material_name = "green" [[hitables]] type = "sphere" center = [30.0, 0.0, 0.0] radius = 10 +material_name = "blue" [[hitables]] type = "stl" path = "/net/nasx.h.xinu.tv/x/3dprint/stl/stanford_dragon.stl" scale = 200 +material_name = "red" [envmap] path = "/home/wathiede/src/xinu.tv/raytracers/rtiow/renderer/images/52681723945_e1d94d3df9_6k.jpg"