summaryrefslogtreecommitdiff
path: root/racer-tracer
diff options
context:
space:
mode:
Diffstat (limited to 'racer-tracer')
-rw-r--r--racer-tracer/config.yml1
-rw-r--r--racer-tracer/scene.yml53
-rw-r--r--racer-tracer/src/config.rs18
-rw-r--r--racer-tracer/src/error.rs8
-rw-r--r--racer-tracer/src/main.rs64
-rw-r--r--racer-tracer/src/material.rs4
-rw-r--r--racer-tracer/src/scene.rs100
-rw-r--r--racer-tracer/src/vec3.rs5
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],
}