From 388c48d236012649730f6f6e62ea0f9ab6aeb20c Mon Sep 17 00:00:00 2001 From: Max Nuding Date: Sat, 2 Jul 2022 06:32:03 +0200 Subject: [PATCH] Positional camera --- src/camera.rs | 56 +++++++++++++++++---------- src/main.rs | 103 ++++++++++++++++++++++++++++++-------------------- src/vec3.rs | 13 +++++++ 3 files changed, 111 insertions(+), 61 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 07edf10..86b2f7a 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -4,42 +4,56 @@ pub struct Camera { aspect_ratio: f64, viewport_height: f64, viewport_width: f64, - focal_length: f64, origin: Point3, horizontal: Vec3, vertical: Vec3, - lower_left_corner: Vec3 + lower_left_corner: Vec3, + lens_radius: f64, + u: Vec3, + v: Vec3, + w: Vec3 } impl Camera { - pub fn get_ray(&self, u: f64, v: f64) -> Ray { + pub fn get_ray(&self, s: f64, t: f64) -> Ray { + let rd = self.lens_radius * Vec3::random_unit_disk(); + let offset = self.u * rd.x() + self.v * rd.y(); Ray::new( - self.origin, - self.lower_left_corner + u*self.horizontal + v*self.vertical - self.origin) + self.origin + offset, + self.lower_left_corner + s*self.horizontal + t*self.vertical - self.origin - offset) } - pub fn new(aspect_ratio: f64) -> Self { - let viewport_height = 2.0; + pub fn new( + look_from: Point3, + look_at: Point3, + up: Vec3, + aspect_ratio: f64, + vfov: f64, + aperture: f64, + focus_dist: f64) -> Self { + + let theta = vfov.to_radians(); + let h = (theta / 2.0).tan(); + let viewport_height = 2.0 * h; let viewport_width = aspect_ratio * viewport_height; - let origin = Point3::default(); - let horizontal = Vec3::new(viewport_width, 0.0, 0.0); - let vertical = Vec3::new(0.0, viewport_height, 0.0); - let focal_length = 1.0; + + let w = (look_from - look_at).unit_vector(); + let u = up.cross(&w).unit_vector(); + let v = w.cross(&u); + + let horizontal = focus_dist * viewport_width * u; + let vertical = focus_dist * viewport_height * v; Camera { aspect_ratio, viewport_height, viewport_width, - focal_length, - origin, + origin: look_from, horizontal, vertical, - lower_left_corner: origin - horizontal/2.0 - vertical/2.0 - Vec3::new(0.0, 0.0, focal_length) + lower_left_corner: look_from - horizontal/2.0 - vertical/2.0 - focus_dist*w, + lens_radius: aperture / 2.0, + u, + v, + w } } } - -impl Default for Camera { - fn default() -> Self { - let aspect_ratio = 16.0 / 9.0; - Camera::new(aspect_ratio) - } -} diff --git a/src/main.rs b/src/main.rs index 322f2a6..5d5e534 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,59 +8,79 @@ use crate::material::{Dielectric, Lambertian, Material, Metal}; mod vec3; mod ray; mod hittable; -mod camera; mod material; +mod camera; + +fn random_scene() -> Vec> { + let mut world:Vec> = Vec::new(); + + let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5))); + let ground = Sphere { + center: Point3::new(0.0, -1000.0, 0.0), + radius: 1000.0, + material: material_ground + }; + world.push(Box::new(ground)); + + let unit_range = Uniform::from(0.0..1.0); + let fuzz_range = Uniform::from(0.0..0.5); + let mut rng = rand::thread_rng(); + let p = Point3::new(4.0, 0.2, 0.0); + for a in -1..11 { + for b in -11..11 { + let choose_material = unit_range.sample(&mut rng); + let center = Point3::new( + (a as f64) + 0.9*unit_range.sample(&mut rng), + 0.2, + (b as f64) + 0.9*unit_range.sample(&mut rng)); + if (center - p).length() < 0.9 { + continue; + } + let material = match choose_material { + _ if choose_material < 0.8 => Material::Lambertian(Lambertian::new( + Color::random(0.0, 1.0) * Color::random(0.0, 1.0))), + _ if choose_material < 0.95 => Material::Metal(Metal::new( + Color::random(0.5, 1.0), + fuzz_range.sample(&mut rng))), + _ => Material::Dielectric(Dielectric::new(1.5)), + }; + let sphere = Box::new(Sphere { + center, + radius: 0.2, + material + }); + world.push(sphere); + } + } + world +} fn main() { // Image - const ASPECT_RATIO: f64 = 16.0 / 9.0; - const IMAGE_WIDTH: i32 = 400; + const ASPECT_RATIO: f64 = 3.0 / 2.0; + const IMAGE_WIDTH: i32 = 1200; const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32; const SAMPLES_PER_PIXEL: i32 = 10; const MAX_DEPTH: i32 = 50; + let look_from = Point3::new(13.0, 2.0, 3.0); + let look_at = Point3::new(0.0, 0.0, 0.0); + let focus_dist = 10.0; // Camera - let cam = Camera::new(ASPECT_RATIO); + let cam = Camera::new( + look_from, + look_at, + Vec3::new(0.0, 1.0, 0.0), + ASPECT_RATIO, + 20.0, + 0.1, + focus_dist); // World - let mut world:Vec> = Vec::new(); - - let center = Box::new(Sphere { - center: Point3::new(0.0, 0.0, -1.0), - radius: 0.5, - material: Material::Lambertian(Lambertian::new(Color::new(0.7, 0.3, 0.3))) - }); - let center_glass = Box::new(Sphere { - center: Point3::new(0.0, 0.0, -1.0), - radius: 0.5, - material: Material::Dielectric(Dielectric::new(1.5)) - }); - world.push(center_glass); - let ground = Sphere { - center: Point3::new(0.0, -100.5, -1.0), - radius: 100.0, - material: Material::Lambertian(Lambertian::new(Color::new(0.8, 0.8, 0.0))) - }; - world.push(Box::new(ground)); - let left = Box::new(Sphere { - center: Point3::new(-1.0, 0.0, -1.0), - radius: 0.5, - material: Material::Metal(Metal::new(Color::new(0.8, 0.8, 0.8), 0.3)) - }); - let left_glass = Box::new(Sphere { - center: Point3::new(-1.0, 0.0, -1.0), - radius: 0.5, - material: Material::Dielectric(Dielectric::new(1.5)) - }); - world.push(left_glass); - let right = Box::new(Sphere { - center: Point3::new(1.0, 0.0, -1.0), - radius: 0.5, - material: Material::Metal(Metal::new(Color::new(0.8, 0.6, 0.2), 1.0)) - }); - world.push(right); + let world= random_scene(); println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); + let between = Uniform::from(0.0..1.0); let mut rng = rand::thread_rng(); for j in (0..IMAGE_HEIGHT).rev() { @@ -72,6 +92,9 @@ fn main() { let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; let ray = cam.get_ray(u, v); + if i == 200 && (j == 112 || j == 113) { + let tt = 0; + } color += ray.pixel_color(&world, MAX_DEPTH); } color.write_color(SAMPLES_PER_PIXEL); diff --git a/src/vec3.rs b/src/vec3.rs index 88c26fa..3788ba6 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -63,6 +63,19 @@ impl Vec3 { } } pub fn random_unit_vector() -> Self { Vec3::random_in_unit_sphere().unit_vector() } + pub fn random_unit_disk() -> Self { + let between = Uniform::from(-1.0..1.0); + let mut rng = rand::thread_rng(); + loop { + let v = Vec3::new( + between.sample(&mut rng), + between.sample(&mut rng), + 0.0); + if v.length_squared() < 1.0 { + return v; + } + } + } pub fn near_zero(&self) -> bool { const MAXIMUM_DISTANCE_FROM_ZERO:f64 = 1e-8; self.x.abs() < MAXIMUM_DISTANCE_FROM_ZERO &&