summaryrefslogtreecommitdiff
path: root/racer-tracer
diff options
context:
space:
mode:
Diffstat (limited to 'racer-tracer')
-rw-r--r--racer-tracer/Cargo.toml2
-rw-r--r--racer-tracer/config.yml16
-rw-r--r--racer-tracer/src/config.rs54
-rw-r--r--racer-tracer/src/error.rs4
-rw-r--r--racer-tracer/src/image.rs14
-rw-r--r--racer-tracer/src/main.rs42
-rw-r--r--racer-tracer/src/render.rs68
7 files changed, 118 insertions, 82 deletions
diff --git a/racer-tracer/Cargo.toml b/racer-tracer/Cargo.toml
index 9bd6b6a..0e80de3 100644
--- a/racer-tracer/Cargo.toml
+++ b/racer-tracer/Cargo.toml
@@ -13,3 +13,5 @@ rayon = "1.6.1"
structopt = "0.3"
num_cpus = "1.15.0"
synchronoise = "1.0.1"
+config = "0.13.3"
+serde = { version = "1", features = ["derive"] }
diff --git a/racer-tracer/config.yml b/racer-tracer/config.yml
new file mode 100644
index 0000000..5719ee3
--- /dev/null
+++ b/racer-tracer/config.yml
@@ -0,0 +1,16 @@
+preview:
+ samples: 2
+ max_depth: 4
+ recurse_depth: 4
+ scale: 4
+
+render:
+ samples: 1000
+ max_depth: 40
+ recurse_depth: 4
+ scale: 1
+
+screen:
+ width: 1280
+ height: 720
+
diff --git a/racer-tracer/src/config.rs b/racer-tracer/src/config.rs
new file mode 100644
index 0000000..109528a
--- /dev/null
+++ b/racer-tracer/src/config.rs
@@ -0,0 +1,54 @@
+use config::File;
+use serde::Deserialize;
+use structopt::StructOpt;
+
+use crate::error::TracerError;
+
+#[derive(Default, Debug, Deserialize)]
+pub struct Screen {
+ pub height: usize,
+ pub width: usize,
+}
+
+#[derive(Default, Debug, Deserialize)]
+pub struct RenderData {
+ pub samples: usize,
+ pub max_depth: usize,
+ pub recurse_depth: usize,
+ pub scale: usize,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "racer-tracer")]
+pub struct Args {
+ #[structopt(
+ short = "c",
+ long = "config",
+ default_value = "./config.yml",
+ env = "CONFIG"
+ )]
+ pub config: String,
+}
+
+#[derive(Default, Debug, Deserialize)]
+pub struct Config {
+ #[serde(default)]
+ pub preview: RenderData,
+
+ #[serde(default)]
+ pub render: RenderData,
+
+ #[serde(default)]
+ pub screen: Screen,
+}
+
+impl Config {
+ pub fn from_file(file: String) -> Result<Self, TracerError> {
+ config::Config::builder()
+ .add_source(File::from(file.as_ref()))
+ .build()
+ .map_err(|e| TracerError::Configuration(file.clone(), e.to_string()))?
+ .try_deserialize()
+ .map_err(|e| TracerError::Configuration(file, e.to_string()))
+ }
+}
diff --git a/racer-tracer/src/error.rs b/racer-tracer/src/error.rs
index 9254715..70a9ab2 100644
--- a/racer-tracer/src/error.rs
+++ b/racer-tracer/src/error.rs
@@ -13,6 +13,9 @@ pub enum TracerError {
#[error("Resolution is not power of two.")]
ResolutionIsNotPowerOfTwo(),
+
+ #[error("Config Error ({0}): {1}")]
+ Configuration(String, String),
}
impl From<TracerError> for i32 {
@@ -25,6 +28,7 @@ impl From<TracerError> for i32 {
TracerError::FailedToCreateWindow(_) => 2,
TracerError::FailedToUpdateWindow(_) => 3,
TracerError::ResolutionIsNotPowerOfTwo() => 4,
+ TracerError::Configuration(_, _) => 5,
}
}
}
diff --git a/racer-tracer/src/image.rs b/racer-tracer/src/image.rs
index 502a15a..1df4cc5 100644
--- a/racer-tracer/src/image.rs
+++ b/racer-tracer/src/image.rs
@@ -2,16 +2,14 @@ pub struct Image {
pub aspect_ratio: f64,
pub width: usize,
pub height: usize,
- pub samples_per_pixel: usize,
}
impl Image {
- pub fn new(aspect_ratio: f64, width: usize, samples_per_pixel: usize) -> Image {
+ pub fn new(width: usize, height: usize) -> Image {
Image {
- aspect_ratio,
+ aspect_ratio: width as f64 / height as f64,
width,
- height: (width as f64 / aspect_ratio) as usize,
- samples_per_pixel,
+ height,
}
}
}
@@ -24,7 +22,6 @@ impl From<&Image> for SubImage {
y: 0,
width: image.width,
height: image.height,
- samples: image.samples_per_pixel,
screen_width: image.width,
screen_height: image.height,
}
@@ -38,7 +35,6 @@ pub struct SubImage {
pub screen_height: usize,
pub width: usize,
pub height: usize,
- pub samples: usize,
}
pub trait QuadSplit {
@@ -57,7 +53,6 @@ impl QuadSplit for SubImage {
y: self.y,
width: half_w,
height: half_h,
- samples: self.samples,
screen_width: self.screen_width,
screen_height: self.screen_height,
},
@@ -67,7 +62,6 @@ impl QuadSplit for SubImage {
y: self.y,
width: half_w,
height: half_h,
- samples: self.samples,
screen_width: self.screen_width,
screen_height: self.screen_height,
},
@@ -77,7 +71,6 @@ impl QuadSplit for SubImage {
y: self.y + half_h,
width: half_w,
height: half_h,
- samples: self.samples,
screen_width: self.screen_width,
screen_height: self.screen_height,
},
@@ -87,7 +80,6 @@ impl QuadSplit for SubImage {
y: self.y + half_h,
width: half_w,
height: half_h,
- samples: self.samples,
screen_width: self.screen_width,
screen_height: self.screen_height,
},
diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs
index 5331fd1..83d2408 100644
--- a/racer-tracer/src/main.rs
+++ b/racer-tracer/src/main.rs
@@ -1,6 +1,7 @@
#[macro_use]
mod error;
mod camera;
+mod config;
mod geometry;
mod image;
mod material;
@@ -22,6 +23,7 @@ use synchronoise::SignalEvent;
use crate::{
camera::Camera,
+ config::{Args, Config},
error::TracerError,
geometry::sphere::Sphere,
geometry::Hittable,
@@ -75,14 +77,11 @@ fn create_scene() -> Scene {
scene
}
-fn run(
- aspect_ratio: f64,
- screen_width: usize,
- samples: usize,
- max_depth: usize,
- recurse_depth: usize,
-) -> Result<(), TracerError> {
- let image = image::Image::new(aspect_ratio, screen_width, samples);
+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 screen_buffer: Arc<RwLock<Vec<u32>>> =
@@ -103,12 +102,6 @@ fn run(
rayon::scope(|s| {
s.spawn(|_| {
- // TODO: Make configurable
- let preview_scale = 4;
- let preview_samples = 2;
- let preview_max_depth = 4;
- let preview_recurse_depth = 4;
-
loop {
if exit.wait_timeout(Duration::from_secs(0)) {
return;
@@ -122,9 +115,7 @@ fn run(
Arc::clone(&camera),
&sub_image,
Arc::clone(&scene),
- samples,
- 1,
- max_depth,
+ Arc::clone(&render_data),
recurse_depth,
Some(cancel_render_event),
);
@@ -140,11 +131,8 @@ fn run(
Arc::clone(&camera),
&sub_image,
Arc::clone(&scene),
- preview_samples,
- preview_scale,
- preview_max_depth,
- // TODO: Could create a function to create the optimal value
- preview_recurse_depth, //recursive thread depth
+ Arc::clone(&preview_render_data),
+ recurse_depth,
None,
);
}
@@ -218,13 +206,11 @@ fn run(
let res = (window_res.lock().expect("Failed to get result lock.")).clone();
res
}
-
+use structopt::StructOpt;
fn main() {
- // TODO: Read configuration and args
- let samples = 1000; // Samples per pixel
- let max_depth = 50; // Max ray trace depth
- let recurse_depth = 4; // How many times the screen with split itself into sub images each time splitting it into 4 new smaller ones.
- if let Err(e) = run(16.0 / 9.0, 1280, samples, max_depth, recurse_depth) {
+ let args = Args::from_args();
+
+ if let Err(e) = Config::from_file(args.config).and_then(run) {
eprintln!("{}", e);
std::process::exit(e.into())
}
diff --git a/racer-tracer/src/render.rs b/racer-tracer/src/render.rs
index c5013cf..ea5c17d 100644
--- a/racer-tracer/src/render.rs
+++ b/racer-tracer/src/render.rs
@@ -9,6 +9,7 @@ use synchronoise::SignalEvent;
use crate::{
camera::Camera,
+ config::RenderData,
geometry::Hittable,
image::{QuadSplit, SubImage},
ray::Ray,
@@ -26,18 +27,14 @@ fn ray_color(scene: &dyn Hittable, ray: &Ray, depth: usize) -> Vec3 {
return attenuation * ray_color(scene, &scattered, depth - 1);
}
return Color::default();
- //let target = rec.point + random_in_hemisphere(&rec.normal);
- //let target = rec.point + rec.normal + random_unit_vector();
- //return 0.5 * ray_color(scene, &Ray::new(rec.point, target - rec.point), depth - 1);
- //return hit_record.color;
- //return 0.5 * (hit_record.normal + Vec3::new(1.0, 1.0, 1.0));
}
- // TODO: make sky part of scene.
// Sky
+ let first_color = Vec3::new(1.0, 1.0, 1.0);
+ let second_color = Vec3::new(0.5, 0.7, 1.0);
let unit_direction = ray.direction().unit_vector();
let t = 0.5 * (unit_direction.y() + 1.0);
- (1.0 - t) * Vec3::new(1.0, 1.0, 1.0) + t * Vec3::new(0.5, 0.7, 1.0)
+ (1.0 - t) * first_color + t * second_color
}
pub fn raytrace(
@@ -46,16 +43,14 @@ pub fn raytrace(
scene: &dyn Hittable,
camera: &Camera,
image: &SubImage,
- samples: usize,
- scale: usize,
- max_depth: usize,
+ data: &RenderData,
) {
// TODO: This scale shit doesn't work.
// Just force power of two or other solutions to avoid this.
// Can be ok for preview but the actual render could use a different function.
- let mut scaled_width = image.width / scale;
- let mut scaled_height = image.height / scale;
+ let mut scaled_width = image.width / data.scale;
+ let mut scaled_height = image.height / data.scale;
// In the case where we get an odd one out we patch the widht and
// height with the esception of the edges of the screen. Without
// this everything has to be power of 2 which isn't a crazy
@@ -64,32 +59,32 @@ pub fn raytrace(
// Biggest problem is that the width and height we get here is
// depending on resolution and how many times the image is split
// up between threads.
- if scaled_width * scale != image.width
- && (image.x + scaled_width * scale + 1 < image.screen_width)
+ if scaled_width * data.scale != image.width
+ && (image.x + scaled_width * data.scale + 1 < image.screen_width)
{
scaled_width += 1;
}
- if scaled_height * scale != image.height
- && (image.y + scaled_height * scale + 1 < image.screen_height)
+ if scaled_height * data.scale != image.height
+ && (image.y + scaled_height * data.scale + 1 < image.screen_height)
{
scaled_height += 1;
}
- let scaled_screen_width = image.screen_width / scale;
- let scaled_screen_height = image.screen_height / scale;
+ let scaled_screen_width = image.screen_width / data.scale;
+ let scaled_screen_height = image.screen_height / data.scale;
let mut colors: Vec<Vec3> = vec![Vec3::default(); scaled_height * scaled_width as usize];
for row in 0..scaled_height {
for column in 0..scaled_width {
- let u: f64 = ((image.x / scale + column) as f64 + random_double())
+ let u: f64 = ((image.x / data.scale + column) as f64 + random_double())
/ (scaled_screen_width - 1) as f64;
- for _ in 0..samples {
- let v: f64 = ((image.y / scale + row) as f64 + random_double())
+ for _ in 0..data.samples {
+ let v: f64 = ((image.y / data.scale + row) as f64 + random_double())
/ (scaled_screen_height - 1) as f64;
colors[row * scaled_width + column].add(ray_color(
scene,
&camera.get_ray(u, v),
- max_depth,
+ data.max_depth,
));
}
}
@@ -111,14 +106,14 @@ pub fn raytrace(
for half_row in 0..scaled_height {
for half_col in 0..scaled_width {
let color = colors[half_row * scaled_width + half_col]
- .scale_sqrt(samples)
+ .scale_sqrt(data.samples)
.as_color();
- let row = half_row * scale;
- let col = half_col * scale;
+ let row = half_row * data.scale;
+ let col = half_col * data.scale;
- for scale_x in 0..scale {
- for scale_y in 0..scale {
+ for scale_x in 0..data.scale {
+ for scale_y in 0..data.scale {
buf[offset + (row + scale_x) * image.screen_width + col + scale_y] = color;
}
}
@@ -138,9 +133,7 @@ pub fn render(
camera: Arc<RwLock<Camera>>,
image: &SubImage,
scene: Arc<Box<dyn Hittable>>,
- samples: usize,
- scale: usize,
- max_depth: usize,
+ data: Arc<RenderData>,
split_depth: usize,
cancel_event: Option<Arc<SignalEvent>>,
) {
@@ -151,16 +144,7 @@ pub fn render(
if split_depth == 0 {
let scene: &(dyn Hittable) = (*scene).borrow();
let camera = { camera.read().expect("TODO").clone() };
- raytrace(
- &buffer,
- cancel_event,
- scene,
- &camera,
- image,
- samples,
- scale,
- max_depth,
- );
+ raytrace(&buffer, cancel_event, scene, &camera, image, &data);
} else {
// Split into more quads
let quads = image.quad_split();
@@ -170,9 +154,7 @@ pub fn render(
Arc::clone(&camera),
&image,
Arc::clone(&scene),
- samples,
- scale,
- max_depth,
+ Arc::clone(&data),
split_depth - 1,
cancel_event.clone(),
);