diff --git a/src/camera.rs b/src/camera.rs index c9dcf20..bc7b230 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::{BufWriter}; use crate::hittable::HittableList; -use crate::math_utils::{clamp, degrees_to_radians}; +use crate::math_utils::{clamp, degrees_to_radians, random_in_unit_disk}; use crate::ppm_writer::PPMWriter; use crate::types_defined::{Camera, Color, HitRecord, Point, Ray, Vec3}; use rand::rngs::ThreadRng; @@ -19,14 +19,17 @@ impl<'a> Camera<'a> { v_up: Vec3, sample_times: i8, reflect_depth: i8, + defocus_angle : f32, + focal_distance: f32, ppm_file_writer: &'a mut PPMWriter> ) -> Self { - let focal_length = (look_at - center).length(); + // let focal_length = (look_at - center).length(); let theta = degrees_to_radians(fov); let h = f32::tan(theta / 2.); - let viewport_height = 2. * h * focal_length; + let viewport_height = 2. * h * focal_distance; + // let viewport_height = 2. * h * focal_length; let image_height = ((image_width as f32 / aspect_ratio) as i32).max(1); let viewport_width = viewport_height * (image_width as f32 / image_height as f32); @@ -48,11 +51,18 @@ impl<'a> Camera<'a> { // height per pix let viewport_v_delta = viewport_v / (image_height as f32); let viewport_top_left_pixel = - center - focal_length * w - viewport_u / 2.0 - viewport_v / 2.0; + center - focal_distance * w - viewport_u / 2.0 - viewport_v / 2.0; + // center - focal_length * w - viewport_u / 2.0 - viewport_v / 2.0; // padding 0.5* delta u/v let viewport_top_left_pixel_center = viewport_top_left_pixel - viewport_u_delta / 2.0 - viewport_v_delta / 2.0; + + // Calculate the camera defocus disk basis vectors. + let defocus_radius = focal_distance * degrees_to_radians(defocus_angle / 2.0).tan(); + let defocus_disk_u = u * defocus_radius; + let defocus_disk_v = v * defocus_radius; + Camera { image_width, image_height, @@ -65,6 +75,10 @@ impl<'a> Camera<'a> { // focal_length, // viewport_u, // viewport_v, + defocus_angle, + defocus_disk_u, + defocus_disk_v, + viewport_u_delta, viewport_v_delta, viewport_top_left_pixel_center, @@ -87,11 +101,7 @@ impl<'a> Camera<'a> { let mut color = Color::new(0.0, 0.0, 0.0); let rng = &mut rng(); for _ in 0..self.sample_times { - let bias = self.random_square(rng); - let pix_sample = self.viewport_top_left_pixel_center - + (i as f32 + bias.x) * self.viewport_u_delta - + (j as f32 + bias.y) * self.viewport_v_delta; - let r = Ray::new(self.center, pix_sample - self.center); + let r = self.get_ray(i, j); let sample_color = self.ray_color(&r, self.reflect_depth, world); color = color + sample_color; } @@ -114,6 +124,26 @@ impl<'a> Camera<'a> { // img_content } + fn defocus_disk_sample(&self) -> Point { + // Returns a random point in the camera defocus disk. + let p = random_in_unit_disk(); + return self.center + (p.x * self.defocus_disk_u) + (p.y * self.defocus_disk_v); + } + + fn get_ray(&self, i: i32, j: i32) -> Ray { + let rng = &mut rng(); + let bias = self.random_square(rng); + let pix_sample = self.viewport_top_left_pixel_center + + (i as f32 + bias.x) * self.viewport_u_delta + + (j as f32 + bias.y) * self.viewport_v_delta; + let center = if self.defocus_angle < 0. { + self.center + } else { + self.defocus_disk_sample() + }; + Ray::new(center, pix_sample - self.center) + } + fn ray_color(&self, ray: &Ray, depth: i8, world: &HittableList) -> Vec3 { // 反射次数 diff --git a/src/main.rs b/src/main.rs index d751b23..63a8702 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,10 +23,10 @@ fn main() { fn camera_render() { let fov: f32 = 60.; - let scale = 1; + let scale = 2; let width: i32 = 800/scale; let height: i32 = 600/scale; - let sample_times = 50; + let sample_times = 20; let reflect_depth = 20; @@ -44,11 +44,13 @@ fn camera_render() { fov, width, width as f32 / height as f32, - Point::new(-2.0, 0.0, -1.0), + Point::new(-0.0, 0.0, 0.0), Point::new(0.0, 0.0, -1.0), Vec3::new(0., 1., 0.), sample_times, reflect_depth, + 2.0, + 1.0, pw ); // world diff --git a/src/math_utils.rs b/src/math_utils.rs index 0dc0285..3ee490d 100644 --- a/src/math_utils.rs +++ b/src/math_utils.rs @@ -1,7 +1,19 @@ use std::f32::consts::PI; +use rand::{rng, Rng}; + use crate::types_defined::{Ray, Vec3}; +pub fn random_in_unit_disk() -> Vec3 { + let rng = &mut rng(); + loop { + let p = Vec3::new(rng.random_range(-1.0..1.0), rng.random_range(-1.0..1.0), 0.0); + if (p.length_squared() < 1.0) { + return p; + } + } +} + pub fn degrees_to_radians(deg: f32) -> f32 { deg * PI / 180. } diff --git a/src/types_defined.rs b/src/types_defined.rs index d8c75c9..21be19d 100644 --- a/src/types_defined.rs +++ b/src/types_defined.rs @@ -43,6 +43,10 @@ pub struct Camera<'a> { // pub focal_length: Vec3, // pub viewport_u: Vec3, // pub viewport_v: Vec3, + pub defocus_angle: f32, + pub defocus_disk_u: Vec3, + pub defocus_disk_v: Vec3, + pub viewport_u_delta: Vec3, pub viewport_v_delta: Vec3, pub viewport_top_left_pixel_center: Vec3,