aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-02-08 18:26:27 +0100
committerJulian T <julian@jtle.dk>2021-02-08 18:27:00 +0100
commit7ccc82fc0992fc23aee354d687ce009ae0523bea (patch)
tree635f7ffe386c638ef8d5ca0db81a3da8ef0f7cc0
parentdbe5f54957ddc13549a6ce822da95170aa09a0c6 (diff)
Finish depth of field
-rw-r--r--readme.md2
-rw-r--r--src/camera/camera.rs27
-rw-r--r--src/core/vector2.rs18
-rw-r--r--src/core/vector3.rs2
-rw-r--r--src/main.rs12
-rw-r--r--src/render.rs2
-rw-r--r--src/sample/mod.rs12
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<Float>,
}
/// 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<Float>,
/// 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<T: Number> Add for Vector2<T> {
}
}
+impl<T: Number> Mul<T> for Vector2<T> {
+ type Output = Self;
+ fn mul(self, op: T) -> Self::Output {
+ Self::new_xy(
+ self.x * op,
+ self.y * op,
+ )
+ }
+}
+
impl<T: Number> fmt::Display for Vector2<T> {
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<T: Number> fmt::Display for Vector3<T> {
}
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(),
+ )
+ }
}