diff --git a/.gitignore b/.gitignore index 59b2499..a860ebe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target -output.png +*.png .env diff --git a/scenes/bench.json b/scenes/bench.json new file mode 100644 index 0000000..f661b97 --- /dev/null +++ b/scenes/bench.json @@ -0,0 +1,38 @@ +{ + "filename": "testing.png", + "image_width": 800, + "image_height": 600, + "max_depth": 50, + "camera": { + "anti_alias_rate": 16, + "fov": 70.0, + "look_from": [-10, 1, 15], + "look_at": [-11.0, 7.0, 0.0], + "vup": [0.0, 1.0, 0.0], + "defocus_angle": 0, + "focus_dist": 15.68 + }, + "materials": [ + { "type": "lambertian", "albedo": [0.2, 0.2, 0.2], "prob": 0.8 }, + { "type": "lambertian", "albedo": [0.9, 0.9, 0.0], "prob": 1.0, "fuzz": 0.1 }, + { "type": "dielectric", "refraction_index": 1.5}, + { "type": "normal"} + ], + "objects": [ + { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.5, "material": { "type": "metal", "albedo": [0.7, 0.4, 0.2], "prob": 1.0, "fuzz": 0.1 }}, + { "type": "sphere", "center": [-1, 0, -1], "radius": 0.4, "material": 3}, + { "type": "sphere", "center": [1, 0, -1], "radius": 0.5, "material": { "type": "metal", "albedo": [0.8, 0.6, 0.2], "prob": 1.0, "fuzz": 1.0 }}, + { "type": "triangle", "p1": [-4, 0, -4], "p2": [0, 0, -4], "p3": [-2, 2, -4], "material": 1}, + { "type": "triangle", "p1": [0, 0, -4], "p2": [4, 0, -4], "p3": [2, 2, -4], "material": 1}, + { "type": "triangle", "p1": [-2, 2, -4], "p2": [2, 2, -4], "p3": [0, 4, -4], "material": 3}, + { "type": "quad", "p1": [-20, -1, -20], "p2": [20, -1, -20], "p3": [20, 20, -20], "p4": [-20, 20, -20], "material": 0}, + { "type": "quad", "p1": [-20, -1, 20], "p2": [-20, -1, -20], "p3": [-20, 20, -20], "p4": [-20, 20, 20], "material": 0}, + { "type": "quad", "p1": [-20, -1, 20], "p2": [20, -1, 20], "p3": [20, -1, -20], "p4": [-20, -1, -20], "material": 0}, + { "type": "quad", "p1": [20, -1, 20], "p2": [20, -1, -20], "p3": [20, 20, -20], "p4": [20, 20, 20], "material": 0}, + { "type": "cube", "p1": [8, 0, 2], "p2": [12, 0, 2], "p3": [12, 4, 2], "p4": [8, 4, 2], "p5": [8, 0, -2], "p6": [12, 0, -2], "p7": [12, 4, -2], "p8": [8, 4, -2], "material": 3}, + { "type": "circle", "center": [-9, 3, 0], "radius": 3, "normal": [0, 1, 0.5], "material": {"type": "metal", "albedo": [0.9, 0.9, 0.9], "prob": 1.0, "fuzz": 0.3}} + ] +} + + + diff --git a/src/camera.rs b/src/camera.rs index f965798..b9f10d1 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,4 @@ -use std::f32::consts::PI; +use std::{f32::consts::PI}; use crate::{ray::Ray, vec3::Vec3}; @@ -6,18 +6,18 @@ use crate::{ray::Ray, vec3::Vec3}; pub struct Camera { // raytracing pub anti_alias_rate: u32, - pub pixel00_loc: Vec3, - pub pixel_delta_u: Vec3, - pub pixel_delta_v: Vec3, + pixel00_loc: Vec3, + pixel_delta_u: Vec3, + pixel_delta_v: Vec3, // camera dirty: bool, - pub fov: f32, - pub look_from: Vec3, - pub look_at: Vec3, + fov: f32, + look_from: Vec3, + look_at: Vec3, vup: Vec3, - pub defocus_angle: f32, - pub focus_dist: f32, + defocus_angle: f32, + focus_dist: f32, // camera helpers u: Vec3, @@ -115,6 +115,14 @@ impl Camera { } } + pub fn get_anti_alias_rate(&self) -> u32 { + self.anti_alias_rate + } + + pub fn get_pixel_tl(&self, x: u32, y: u32) -> Vec3 { + return self.pixel00_loc + (x * self.pixel_delta_u) + (y * self.pixel_delta_v); + } + pub fn get_ray(&self, pixel_tl: Vec3, x: u32, y: u32) -> Ray { let pixel_loc = pixel_tl + (x * self.pixel_delta_u / (self.anti_alias_rate + 1) as f32) diff --git a/src/raytracer.rs b/src/raytracer.rs index b69eaab..60f26bb 100644 --- a/src/raytracer.rs +++ b/src/raytracer.rs @@ -2,7 +2,7 @@ use image::{ExtendedColorType, ImageEncoder, codecs::png::PngEncoder}; use log::{error, info}; use rayon::iter::IntoParallelIterator; use rayon::prelude::*; -use std::{fs::File, sync::Arc}; +use std::{fs::File, sync::Arc, time::Instant}; use crate::{ objects::{hit::Hit, traits::Hittable}, @@ -24,8 +24,7 @@ pub fn write_image(filename: &str, pixels: &[u8], width: u32, height: u32) { } pub fn render(scene: &mut Scene) { - let camera = &mut scene.camera; - camera.init(scene.image_width as f32, scene.image_height as f32); + scene.init(); // TODO: currently splits per vertical line, but could be more granular (per chunk) let mut pixels = vec![0 as u8; (scene.image_width * scene.image_height * 3) as usize]; @@ -34,9 +33,11 @@ pub fn render(scene: &mut Scene) { .enumerate() .collect(); + let now = Instant::now(); scanlines.into_par_iter().for_each(|(i, chunk)| { render_chunk(chunk, scene, i as u32); }); + info!("rendering took {}.{} seconds.", now.elapsed().as_secs(), now.elapsed().subsec_nanos()); info!("Writing image file..."); write_image( @@ -48,23 +49,22 @@ pub fn render(scene: &mut Scene) { } pub fn render_chunk(chunk: &mut [u8], scene: &Scene, y: u32) { - let camera = &scene.camera; + let camera = &scene.get_camera(); + let aa_rate = &scene.get_camera().get_anti_alias_rate(); for i in 0..scene.image_width { - let pixel_tl = camera.pixel00_loc + (i * camera.pixel_delta_u) + (y * camera.pixel_delta_v); - // THOUGHT: the above seems more efficient (esp for larger aa rates) but can test for a - // get_ray_no_tl() function and compare performance. + let pixel_tl = camera.get_pixel_tl(i, y); let mut pixel_colour = Colour::default(); - for y in 1..(camera.anti_alias_rate + 1) { - for x in 1..(camera.anti_alias_rate + 1) { + for y in 1..(aa_rate + 1) { + for x in 1..(aa_rate + 1) { let r = camera.get_ray(pixel_tl, x, y); pixel_colour += ray_colour(&scene.objects, &r, scene.max_depth); } } let (r, g, b) = - (pixel_colour / (camera.anti_alias_rate * camera.anti_alias_rate) as f32).output(); + (pixel_colour / (aa_rate * aa_rate) as f32).output(); chunk[(i * 3) as usize] = r; chunk[(i * 3) as usize + 1] = g; chunk[(i * 3) as usize + 2] = b; diff --git a/src/scenes/scene.rs b/src/scenes/scene.rs index 527966a..ef9c8b1 100644 --- a/src/scenes/scene.rs +++ b/src/scenes/scene.rs @@ -38,6 +38,22 @@ impl Scene { max_depth, } } + + pub fn get_camera(&self) -> &Camera { + &self.camera + } + + pub fn get_image_width(&self) -> f32 { + self.image_width as f32 + } + + pub fn get_image_height(&self) -> f32 { + self.image_height as f32 + } + + pub fn init(&mut self) { + self.camera.init(self.get_image_width(), self.get_image_height()); + } } #[derive(Deserialize)]