Feat: Simulate depth-of-field

And with that, I'm on to the final render. Chapter 12 closed!
This commit is contained in:
2023-06-06 19:14:17 -05:00
parent b7ec69dc7f
commit b6ec544b3e
3 changed files with 55 additions and 18 deletions

View File

@@ -14,15 +14,28 @@ use crate::vec3::Vec3;
use crate::ray::Ray; use crate::ray::Ray;
use crate::degrees_to_radians; use crate::degrees_to_radians;
use rand::rngs::SmallRng;
use rand::distributions::Uniform;
pub struct Camera { pub struct Camera {
pub origin: Vec3, origin: Vec3,
pub lower_left_corner: Vec3, lower_left_corner: Vec3,
pub horizontal: Vec3, horizontal: Vec3,
pub vertical: Vec3, vertical: Vec3,
u: Vec3, v: Vec3, w: Vec3,
lens_radius: f32,
} }
impl Camera { 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 theta = degrees_to_radians(vfov);
let h = (theta / 2.0).tan(); let h = (theta / 2.0).tan();
let vp_height = 2.0 * h; let vp_height = 2.0 * h;
@@ -33,25 +46,30 @@ impl Camera {
let v = Vec3::cross(w, u); let v = Vec3::cross(w, u);
let orig = lookfrom; let orig = lookfrom;
let horiz = u * vp_width; let horiz = u * vp_width * focus_dist;
let verti = v * vp_height; let verti = v * vp_height * focus_dist;
let lower_left_corner = orig - horiz / 2.0 - verti / 2.0 - w; let lower_left_corner = orig - horiz / 2.0 - verti / 2.0 - w * focus_dist;
Camera{ Camera{
origin: orig, origin: orig,
lower_left_corner, lower_left_corner,
horizontal: horiz, horizontal: horiz,
vertical: verti, 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<f32>) -> 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 let dir = self.lower_left_corner
+ self.horizontal * s + self.horizontal * s
+ self.vertical * t + self.vertical * t
- self.origin; - self.origin - offset;
Ray{ Ray{
orig: self.origin, orig: self.origin + offset,
dir, dir,
} }
} }

View File

@@ -25,8 +25,8 @@ fn main() {
// image // image
let aspect_ratio = 16.0 / 9.0; let aspect_ratio = 16.0 / 9.0;
let image = ( let image = (
400, 1920,
(400.0 / aspect_ratio) as i32 (1920.0 / aspect_ratio) as i32
); );
let samples_per_pixel = 100; let samples_per_pixel = 100;
let max_depth = 50; let max_depth = 50;
@@ -92,12 +92,19 @@ fn main() {
// camera // 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( let cam = Camera::new(
Vec3::new(-2.0, 2.0, 1.0), lookfrom,
Vec3::new(0.0, 0.0, -1.0), lookat,
Vec3::new(0.0, 1.0, 0.0), vup,
20.0, 20.0,
aspect_ratio aspect_ratio,
aperture,
dist_to_focus
); );
// render // render
@@ -112,7 +119,7 @@ fn main() {
for _ in 0..samples_per_pixel { for _ in 0..samples_per_pixel {
let u = ((x as f32) + small_rng.sample(distrib_zero_one)) / ((image.0 - 1) as f32); 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 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); color+= ray_color(ray, &world, max_depth, &mut small_rng, distrib_plusminus_one);
} }
println!("{}", color.print_ppm(samples_per_pixel)); println!("{}", color.print_ppm(samples_per_pixel));

View File

@@ -61,6 +61,18 @@ impl Vec3{
} }
} }
pub fn rand_in_unit_disk(srng: &mut SmallRng, distrib: Uniform<f32>) -> 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<f32>) -> Vec3 { pub fn rand_unit_vector(srng: &mut SmallRng, distrib: Uniform<f32>) -> Vec3 {
return Vec3::as_unit(Vec3::rand_in_unit_sphere(srng, distrib)); return Vec3::as_unit(Vec3::rand_in_unit_sphere(srng, distrib));
} }