From b6ec544b3ef98fdc4711fb44b8e97bf794ea7c3a Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Tue, 6 Jun 2023 19:14:17 -0500 Subject: [PATCH] Feat: Simulate depth-of-field And with that, I'm on to the final render. Chapter 12 closed! --- src/camera.rs | 40 +++++++++++++++++++++++++++++----------- src/main.rs | 21 ++++++++++++++------- src/vec3.rs | 12 ++++++++++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index a7ed241..3a7bd1f 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -14,15 +14,28 @@ use crate::vec3::Vec3; use crate::ray::Ray; use crate::degrees_to_radians; +use rand::rngs::SmallRng; +use rand::distributions::Uniform; + pub struct Camera { - pub origin: Vec3, - pub lower_left_corner: Vec3, - pub horizontal: Vec3, - pub vertical: Vec3, + origin: Vec3, + lower_left_corner: Vec3, + horizontal: Vec3, + vertical: Vec3, + u: Vec3, v: Vec3, w: Vec3, + lens_radius: f32, } impl Camera { - pub fn new(lookfrom: Vec3, lookat: Vec3, vup: Vec3, vfov: f32, aspect_ratio: f32) -> Camera { + pub fn new( + lookfrom: Vec3, + lookat: Vec3, + vup: Vec3, + vfov: f32, + aspect_ratio: f32, + aperture: f32, + focus_dist: f32 + ) -> Camera { let theta = degrees_to_radians(vfov); let h = (theta / 2.0).tan(); let vp_height = 2.0 * h; @@ -33,25 +46,30 @@ impl Camera { let v = Vec3::cross(w, u); let orig = lookfrom; - let horiz = u * vp_width; - let verti = v * vp_height; - let lower_left_corner = orig - horiz / 2.0 - verti / 2.0 - w; + let horiz = u * vp_width * focus_dist; + let verti = v * vp_height * focus_dist; + let lower_left_corner = orig - horiz / 2.0 - verti / 2.0 - w * focus_dist; Camera{ origin: orig, lower_left_corner, horizontal: horiz, vertical: verti, + u, v, w, + lens_radius: aperture / 2.0, } } - pub fn get_ray(&self, s: f32, t: f32) -> Ray { + pub fn get_ray(&self, s: f32, t: f32, srng: &mut SmallRng, distrib: Uniform) -> Ray { + let rd = Vec3::rand_in_unit_disk(srng, distrib) * self.lens_radius; + let offset = self.u * rd.x + self.v * rd.y; + let dir = self.lower_left_corner + self.horizontal * s + self.vertical * t - - self.origin; + - self.origin - offset; Ray{ - orig: self.origin, + orig: self.origin + offset, dir, } } diff --git a/src/main.rs b/src/main.rs index 222162a..7ed9f3f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,8 +25,8 @@ fn main() { // image let aspect_ratio = 16.0 / 9.0; let image = ( - 400, - (400.0 / aspect_ratio) as i32 + 1920, + (1920.0 / aspect_ratio) as i32 ); let samples_per_pixel = 100; let max_depth = 50; @@ -92,12 +92,19 @@ fn main() { // camera + let lookfrom = Vec3::new(3.0, 3.0, 2.0); + let lookat = Vec3::new(0.0, 0.0, -1.0); + let vup = Vec3::new(0.0, 1.0, 0.0); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 2.0; let cam = Camera::new( - Vec3::new(-2.0, 2.0, 1.0), - Vec3::new(0.0, 0.0, -1.0), - Vec3::new(0.0, 1.0, 0.0), + lookfrom, + lookat, + vup, 20.0, - aspect_ratio + aspect_ratio, + aperture, + dist_to_focus ); // render @@ -112,7 +119,7 @@ fn main() { for _ in 0..samples_per_pixel { let u = ((x as f32) + small_rng.sample(distrib_zero_one)) / ((image.0 - 1) as f32); let v = ((y as f32) + small_rng.sample(distrib_zero_one)) / ((image.1 - 1) as f32); - let ray = cam.get_ray(u, v); + let ray = cam.get_ray(u, v, &mut small_rng, distrib_plusminus_one); color+= ray_color(ray, &world, max_depth, &mut small_rng, distrib_plusminus_one); } println!("{}", color.print_ppm(samples_per_pixel)); diff --git a/src/vec3.rs b/src/vec3.rs index 75078d8..e3b99ab 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -61,6 +61,18 @@ impl Vec3{ } } + pub fn rand_in_unit_disk(srng: &mut SmallRng, distrib: Uniform) -> Vec3 { + loop { + let p = Vec3 { + x: srng.sample(distrib), + y: srng.sample(distrib), + z: 0.0, + }; + if p.length_squared() >= 1.0 { continue; } + else { return p; } + } + } + pub fn rand_unit_vector(srng: &mut SmallRng, distrib: Uniform) -> Vec3 { return Vec3::as_unit(Vec3::rand_in_unit_sphere(srng, distrib)); }