diff options
| author | Sakarias Johansson <sakarias.johansson@goodbyekansas.com> | 2023-01-18 21:01:24 +0100 |
|---|---|---|
| committer | Sakarias Johansson <sakarias.johansson@goodbyekansas.com> | 2023-01-18 21:01:24 +0100 |
| commit | 2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c (patch) | |
| tree | 3b58470a7f382634187ba155a1ed398595247a35 /racer-tracer | |
| parent | 38e9bf130fc1075d576626f0c2ade582ccc3c57f (diff) | |
| download | racer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.tar.gz racer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.tar.xz racer-tracer-2abf48d9ce2968f7e999a9e0faf6d0ebfa752c7c.zip | |
🏙️ Add support for reading scene from file
Diffstat (limited to 'racer-tracer')
| -rw-r--r-- | racer-tracer/config.yml | 1 | ||||
| -rw-r--r-- | racer-tracer/scene.yml | 53 | ||||
| -rw-r--r-- | racer-tracer/src/config.rs | 18 | ||||
| -rw-r--r-- | racer-tracer/src/error.rs | 8 | ||||
| -rw-r--r-- | racer-tracer/src/main.rs | 64 | ||||
| -rw-r--r-- | racer-tracer/src/material.rs | 4 | ||||
| -rw-r--r-- | racer-tracer/src/scene.rs | 100 | ||||
| -rw-r--r-- | racer-tracer/src/vec3.rs | 5 |
8 files changed, 197 insertions, 56 deletions
diff --git a/racer-tracer/config.yml b/racer-tracer/config.yml index 5719ee3..f32f991 100644 --- a/racer-tracer/config.yml +++ b/racer-tracer/config.yml @@ -14,3 +14,4 @@ screen: width: 1280 height: 720 +scene: ./scene.yml diff --git a/racer-tracer/scene.yml b/racer-tracer/scene.yml new file mode 100644 index 0000000..f9e7571 --- /dev/null +++ b/racer-tracer/scene.yml @@ -0,0 +1,53 @@ +--- +materials: + grass: + Lambertian: + color: + data: [ 0.8, 0.8, 0.0 ] + + center: + Lambertian: + color: + data: [ 0.1, 0.2, 0.5 ] + + left: + Dialectric: + refraction_index: 1.5 + + right: + Metal: + color: + data: [ 0.8, 0.6, 0.2] + fuzz: 0.0 + +geometry: + - Sphere: + pos: + data: [ 0.0, -100.5, -1.0 ] + radius: 100.0 + material: grass + + - Sphere: + pos: + data: [ 0.0, 0.0, -1.0 ] + radius: 0.5 + material: center + + - Sphere: + pos: + data: [ -1.0, 0.0, -1.0 ] + radius: 0.5 + material: left + + - Sphere: + pos: + data: [ -1.0, 0.0, -1.0 ] + radius: -0.4 + material: left + + - Sphere: + pos: + data: [ 1.0, 0.0, -1.0 ] + radius: -0.5 + material: right + diff --git a/racer-tracer/src/config.rs b/racer-tracer/src/config.rs index 109528a..79c50eb 100644 --- a/racer-tracer/src/config.rs +++ b/racer-tracer/src/config.rs @@ -28,6 +28,21 @@ pub struct Args { env = "CONFIG" )] pub config: String, + + #[structopt(short = "s", long = "scene")] + pub scene: Option<String>, +} + +impl TryFrom<Args> for Config { + type Error = TracerError; + fn try_from(args: Args) -> Result<Self, TracerError> { + Config::from_file(args.config).map(|mut cfg| { + if args.scene.is_some() { + cfg.scene = args.scene; + } + cfg + }) + } } #[derive(Default, Debug, Deserialize)] @@ -40,6 +55,9 @@ pub struct Config { #[serde(default)] pub screen: Screen, + + #[serde(default)] + pub scene: Option<String>, } impl Config { diff --git a/racer-tracer/src/error.rs b/racer-tracer/src/error.rs index 70a9ab2..f32dac9 100644 --- a/racer-tracer/src/error.rs +++ b/racer-tracer/src/error.rs @@ -16,6 +16,12 @@ pub enum TracerError { #[error("Config Error ({0}): {1}")] Configuration(String, String), + + #[error("Unknown Material {0}.")] + UnknownMaterial(String), + + #[error("No scene supplied.")] + NoScene(), } impl From<TracerError> for i32 { @@ -29,6 +35,8 @@ impl From<TracerError> for i32 { TracerError::FailedToUpdateWindow(_) => 3, TracerError::ResolutionIsNotPowerOfTwo() => 4, TracerError::Configuration(_, _) => 5, + TracerError::UnknownMaterial(_) => 6, + TracerError::NoScene() => 7, } } } diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs index 83d2408..d97e3a1 100644 --- a/racer-tracer/src/main.rs +++ b/racer-tracer/src/main.rs @@ -12,12 +12,12 @@ mod util; mod vec3; use std::{ + convert::TryFrom, sync::{Arc, Mutex, RwLock}, time::{Duration, Instant}, vec::Vec, }; -use material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, Material}; use minifb::{Key, Window, WindowOptions}; use synchronoise::SignalEvent; @@ -25,65 +25,23 @@ use crate::{ camera::Camera, config::{Args, Config}, error::TracerError, - geometry::sphere::Sphere, geometry::Hittable, image::SubImage, render::render, scene::Scene, - vec3::{Color, Vec3}, }; -type SharedMaterial = Arc<Box<dyn Material>>; - -// TODO: Read from yml -fn create_scene() -> Scene { - let mut scene = Scene::new(); - let material_ground: SharedMaterial = - Arc::new(Box::new(Lambertian::new(Color::new(0.8, 0.8, 0.0)))); - let material_center: SharedMaterial = - Arc::new(Box::new(Lambertian::new(Color::new(0.1, 0.2, 0.5)))); - let material_left: SharedMaterial = Arc::new(Box::new(Dialectric::new(1.5))); - - let material_right: SharedMaterial = - Arc::new(Box::new(Metal::new(Color::new(0.8, 0.6, 0.2), 0.0))); - - scene.add(Box::new(Sphere::new( - Vec3::new(0.0, -100.5, -1.0), - 100.0, - Arc::clone(&material_ground), - ))); - scene.add(Box::new(Sphere::new( - Vec3::new(0.0, 0.0, -1.0), - 0.5, - Arc::clone(&material_center), - ))); - scene.add(Box::new(Sphere::new( - Vec3::new(-1.0, 0.0, -1.0), - 0.5, - Arc::clone(&material_left), - ))); - - scene.add(Box::new(Sphere::new( - Vec3::new(-1.0, 0.0, -1.0), - -0.4, - Arc::clone(&material_left), - ))); - - scene.add(Box::new(Sphere::new( - Vec3::new(1.0, 0.0, -1.0), - 0.5, - Arc::clone(&material_right), - ))); - scene -} - fn run(config: Config) -> Result<(), TracerError> { let preview_render_data = Arc::new(config.preview); - let recurse_depth = 4; let render_data = Arc::new(config.render); let image = image::Image::new(config.screen.width, config.screen.height); let camera = Arc::new(RwLock::new(Camera::new(&image, 2.0, 1.0))); - let scene: Arc<Box<dyn Hittable>> = Arc::new(Box::new(create_scene())); + let scene: Arc<Box<dyn Hittable>> = Arc::new(Box::new( + config + .scene + .ok_or(TracerError::NoScene()) + .and_then(Scene::from_file)?, + )); let screen_buffer: Arc<RwLock<Vec<u32>>> = Arc::new(RwLock::new(vec![0; image.width * image.height])); @@ -116,7 +74,7 @@ fn run(config: Config) -> Result<(), TracerError> { &sub_image, Arc::clone(&scene), Arc::clone(&render_data), - recurse_depth, + render_data.recurse_depth, Some(cancel_render_event), ); @@ -132,7 +90,7 @@ fn run(config: Config) -> Result<(), TracerError> { &sub_image, Arc::clone(&scene), Arc::clone(&preview_render_data), - recurse_depth, + preview_render_data.recurse_depth, None, ); } @@ -208,9 +166,7 @@ fn run(config: Config) -> Result<(), TracerError> { } use structopt::StructOpt; fn main() { - let args = Args::from_args(); - - if let Err(e) = Config::from_file(args.config).and_then(run) { + if let Err(e) = Config::try_from(Args::from_args()).and_then(run) { eprintln!("{}", e); std::process::exit(e.into()) } diff --git a/racer-tracer/src/material.rs b/racer-tracer/src/material.rs index a43b29f..1092ebc 100644 --- a/racer-tracer/src/material.rs +++ b/racer-tracer/src/material.rs @@ -2,10 +2,14 @@ pub mod dialectric; pub mod lambertian; pub mod metal; +use std::sync::Arc; + use crate::geometry::HitRecord; use crate::ray::Ray; use crate::vec3::Color; +pub type SharedMaterial = Arc<Box<dyn Material>>; + pub trait Material: Send + Sync { fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Ray, Color)>; } diff --git a/racer-tracer/src/scene.rs b/racer-tracer/src/scene.rs index c5e76da..91fa252 100644 --- a/racer-tracer/src/scene.rs +++ b/racer-tracer/src/scene.rs @@ -1,4 +1,14 @@ -use crate::geometry::Hittable; +use std::{collections::HashMap, path::Path, sync::Arc}; + +use config::File; +use serde::Deserialize; + +use crate::{ + error::TracerError, + geometry::{sphere::Sphere, Hittable}, + material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial}, + vec3::{Color, Vec3}, +}; pub struct Scene { objects: Vec<Box<dyn Hittable>>, @@ -14,6 +24,10 @@ impl Scene { pub fn add(&mut self, hittable: Box<dyn Hittable>) { self.objects.push(hittable); } + + pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, TracerError> { + SceneData::from_file(file)?.try_into() + } } impl Hittable for Scene { @@ -36,3 +50,87 @@ impl Hittable for Scene { rec } } + +#[derive(Debug, Deserialize)] +enum MaterialData { + Lambertian { color: Color }, + Metal { color: Color, fuzz: f64 }, + Dialectric { refraction_index: f64 }, +} + +#[derive(Debug, Deserialize)] +enum GeometryData { + Sphere { + pos: Vec3, + radius: f64, + material: String, + }, +} + +#[derive(Deserialize)] +struct SceneData { + materials: HashMap<String, MaterialData>, + geometry: Vec<GeometryData>, +} + +impl SceneData { + pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, TracerError> { + config::Config::builder() + .add_source(File::from(file.as_ref())) + .build() + .map_err(|e| { + TracerError::Configuration( + file.as_ref().to_string_lossy().into_owned(), + e.to_string(), + ) + })? + .try_deserialize() + .map_err(|e| { + TracerError::Configuration( + file.as_ref().to_string_lossy().into_owned(), + e.to_string(), + ) + }) + } +} + +impl TryInto<Scene> for SceneData { + type Error = TracerError; + fn try_into(self) -> Result<Scene, TracerError> { + let mut materials: HashMap<String, SharedMaterial> = HashMap::new(); + self.materials + .into_iter() + .for_each(|(id, material)| match material { + MaterialData::Lambertian { color } => { + materials.insert(id, Arc::new(Box::new(Lambertian::new(color)))); + } + MaterialData::Metal { color, fuzz } => { + materials.insert(id, Arc::new(Box::new(Metal::new(color, fuzz)))); + } + MaterialData::Dialectric { refraction_index } => { + materials.insert(id, Arc::new(Box::new(Dialectric::new(refraction_index)))); + } + }); + + let geometry: Vec<Box<dyn Hittable>> = self + .geometry + .into_iter() + .map(|geo| match geo { + GeometryData::Sphere { + pos, + radius, + material, + } => materials + .get(&material) + .ok_or(TracerError::UnknownMaterial(material)) + .map(|mat| { + let apa: Box<dyn Hittable> = + Box::new(Sphere::new(pos, radius, Arc::clone(mat))); + apa + }), + }) + .collect::<Result<Vec<Box<dyn Hittable>>, TracerError>>()?; + + Ok(Scene { objects: geometry }) + } +} diff --git a/racer-tracer/src/vec3.rs b/racer-tracer/src/vec3.rs index 9061eba..ed21a45 100644 --- a/racer-tracer/src/vec3.rs +++ b/racer-tracer/src/vec3.rs @@ -1,8 +1,11 @@ use std::{fmt, ops}; +use serde::Deserialize; + use crate::util::{random_double, random_double_range}; -#[derive(Default, Clone, Copy)] +// TODO: Remove clone and copy. We want to be aware when this happens to save time. +#[derive(Default, Clone, Copy, Deserialize)] pub struct Vec3 { data: [f64; 3], } |
