From 7ccc82fc0992fc23aee354d687ce009ae0523bea Mon Sep 17 00:00:00 2001 From: Julian T Date: Mon, 8 Feb 2021 18:26:27 +0100 Subject: Finish depth of field --- readme.md | 2 +- src/camera/camera.rs | 27 +++++++++++++++++++++------ src/core/vector2.rs | 18 +++++++++++++++++- src/core/vector3.rs | 2 ++ src/main.rs | 12 ++++++------ src/render.rs | 2 +- src/sample/mod.rs | 12 ++++++++++++ 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/readme.md b/readme.md index b535d79..6176e25 100644 --- a/readme.md +++ b/readme.md @@ -19,7 +19,7 @@ I never really finished it before changing to rust. ## Goals +- [X] Render collection of circles outside, with blurry background - [ ] Render [Cornell box](https://en.wikipedia.org/wiki/Cornell_box) -- [ ] Render collection of circles outside, with blurry background - [ ] Render [Utah teapot](https://en.wikipedia.org/wiki/Utah_teapot) - [ ] Render [Stanford dragon](https://en.wikipedia.org/wiki/Stanford_dragon) diff --git a/src/camera/camera.rs b/src/camera/camera.rs index e770efe..4d05e87 100644 --- a/src/camera/camera.rs +++ b/src/camera/camera.rs @@ -33,6 +33,7 @@ //! ``` use crate::Float; use crate::core::{Vector3f, Vector2f, Vector2i, Ray}; +use crate::sample::Sampler; /// A simple perspective camera pub struct Camera { @@ -43,6 +44,9 @@ pub struct Camera { /// Scaling vectors from screen_origin qx: Vector3f, qy: Vector3f, + + /// Value for depth of view + lens_radius: Option, } /// Settings for initializing camera @@ -59,7 +63,9 @@ pub struct CameraSettings { /// The film aspect ratio, height / width pub filmsize: Vector2i, /// The lens aperture - pub aperture: Float, + /// + /// Depth of view is disabled if None + pub aperture: Option, /// The distance to the focus plane /// /// if None it will be set to the distance between origin and target @@ -96,22 +102,31 @@ impl Camera { screen_origin, qx, qy, + lens_radius: set.aperture.map(|a| a / 2.0), } } /// Generates a ray a screen space point /// - /// The point coordinates should be between [0,1) with (0, 0) being the upper let corner + /// The point coordinates should be between [0,1) with (0, 0) being the upper left corner /// /// Will return a ray and a weight /// /// The direction of the returned way is normalized - pub fn generate_ray(&self, point: &Vector2f) -> (Ray, Float) { - let mut dir = self.screen_origin + (self.qx * point.x) - (self.qy * point.y); - dir.norm_in(); + pub fn generate_ray(&self, point: &Vector2f, sampler: &mut dyn Sampler) -> (Ray, Float) { + // Depth of view origin offset + let ooffset = match self.lens_radius { + Some(r) => { + let rand_dir = sampler.get_in_circle() * r; + self.qx * rand_dir.x + self.qy * rand_dir.y + }, + None => Vector3f::ZERO, + }; + + let dir = self.screen_origin + (self.qx * point.x) - (self.qy * point.y) - ooffset; ( - Ray { origin: self.origin, direction: dir }, + Ray { origin: self.origin + ooffset, direction: dir.norm() }, 1.0 ) } diff --git a/src/core/vector2.rs b/src/core/vector2.rs index b3fa443..7e40394 100644 --- a/src/core/vector2.rs +++ b/src/core/vector2.rs @@ -2,7 +2,7 @@ //! //! This is implemented generictly with types that fit in the Number trait use crate::{Float, Number}; -use std::ops::{Sub, Add}; +use std::ops::{Sub, Add, Mul}; use std::fmt; use std::cmp::min; @@ -45,6 +45,16 @@ impl Add for Vector2 { } } +impl Mul for Vector2 { + type Output = Self; + fn mul(self, op: T) -> Self::Output { + Self::new_xy( + self.x * op, + self.y * op, + ) + } +} + impl fmt::Display for Vector2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_fmt(format_args!("[{}, {}]", self.x, self.y)) @@ -94,6 +104,12 @@ impl Vector2i { } } +impl Vector2f { + pub fn len(&self) -> Float { + (self.x*self.x + self.y*self.y).sqrt() + } +} + #[cfg(test)] mod tests { diff --git a/src/core/vector3.rs b/src/core/vector3.rs index 1ae4db2..24b84e9 100644 --- a/src/core/vector3.rs +++ b/src/core/vector3.rs @@ -108,6 +108,8 @@ impl fmt::Display for Vector3 { } impl Vector3f { + pub const ZERO: Self = Vector3f {x: 0.0, y: 0.0, z: 0.0}; + /// Calculates the length times itself /// /// This is faster than using len * len as the square is ommited diff --git a/src/main.rs b/src/main.rs index 1707360..e606cba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,18 +13,18 @@ fn main() { let res = Vector2i::new_xy(500, 500); let cam = Camera::new(&CameraSettings { - target: Vector3f::new_xyz(0.5, 0.0, -1.0), - origin: Vector3f::new_xyz(1.7, 0.0, 0.0), + target: Vector3f::new_xyz(0.0, 0.0, -1.0), + origin: Vector3f::new_xyz(1.7, 0.0, 0.3), up: Vector3f::new_xyz(0.0, 1.0, 0.0), - fov: 90.0, + fov: 40.0, filmsize: res, focus: None, - aperture: 0.5, + aperture: Some(20.0), }); let brown = Rc::new(Lambertian::new(Spectrum::new_rgb(0.5, 0.3, 0.0))); let blue = Rc::new(Lambertian::new(Spectrum::new_rgb(0.0, 0.3, 0.7))); - let metal = Rc::new(Reflectant::new(Spectrum::new_rgb(0.75, 0.75, 0.75), Some(0.1))); + let metal = Rc::new(Reflectant::new(Spectrum::new_rgb(0.75, 0.75, 0.75), None)); let mut scn = Scene::new(); scn.add_objects(vec![ @@ -42,7 +42,7 @@ fn main() { let mut film = Film::new(res); let tile = film.get_tile(&film.frame); - let mut task = RenderTask::new(Box::new(tile), 10); + let mut task = RenderTask::new(Box::new(tile), 100); task.render(&ctx, &mut sampler); film.commit_tile(&task.tile); diff --git a/src/render.rs b/src/render.rs index 23b80ae..9a6b905 100644 --- a/src/render.rs +++ b/src/render.rs @@ -31,7 +31,7 @@ impl RenderTask { let p = corner + sampler.get_sample_2d(); // Create a ray - let (r, _) = ctx.cam.generate_ray(&p); + let (r, _) = ctx.cam.generate_ray(&p, sampler); self.tile.add_sample(&p, ctx.trc.trace(sampler, &r)); } diff --git a/src/sample/mod.rs b/src/sample/mod.rs index 5095501..88e1aa9 100644 --- a/src/sample/mod.rs +++ b/src/sample/mod.rs @@ -29,4 +29,16 @@ pub trait Sampler { costheta, ) } + + fn get_in_circle(&mut self) -> Vector2f { + let s2d = self.get_sample_2d(); + + let d = s2d.x.sqrt(); + let theta = s2d.y * 2.0 * M_PI; + + Vector2f::new_xy( + d * theta.cos(), + d * theta.sin(), + ) + } } -- cgit v1.2.3