extern crate rand; use std::f32::consts::PI; use self::rand::Rng; use crate::ray::Ray; use crate::vec3::cross; use crate::vec3::Vec3; fn random_in_unit_disk() -> Vec3 { let mut rng = rand::thread_rng(); let v = Vec3::new(1., 1., 0.); loop { let p = 2. * Vec3::new( rng.gen_range::(0., 1.), rng.gen_range::(0., 1.), 0., ) - v; if p.squared_length() < 1. { return p; } } } pub struct Camera { origin: Vec3, lower_left_corner: Vec3, horizontal: Vec3, vertical: Vec3, u: Vec3, v: Vec3, lens_radius: f32, time_min: f32, time_max: f32, } impl Camera { // Parameters match the example C++ code. #[allow(clippy::too_many_arguments)] // vfov is top to bottom in degrees pub fn new( lookfrom: Vec3, lookat: Vec3, vup: Vec3, vfov: f32, aspect: f32, aperture: f32, focus_dist: f32, time_min: f32, time_max: f32, ) -> Camera { let theta = vfov * PI / 180.; let half_height = (theta / 2.).tan(); let half_width = aspect * half_height; let origin = lookfrom; let w = (lookfrom - lookat).unit_vector(); let u = cross(vup, w).unit_vector(); let v = cross(w, u); Camera { lower_left_corner: origin - half_width * focus_dist * u - half_height * focus_dist * v - focus_dist * w, horizontal: 2. * half_width * focus_dist * u, vertical: 2. * half_height * focus_dist * v, origin, u: cross(vup, w).unit_vector(), v: cross(w, u), lens_radius: aperture / 2., time_min, time_max, } } pub fn get_ray(&self, u: f32, v: f32) -> Ray { let mut rng = rand::thread_rng(); let rd = self.lens_radius * random_in_unit_disk(); let offset = self.u * rd.x + self.v * rd.y; let time = self.time_min + rng.gen_range::(0., 1.) * (self.time_max - self.time_min); Ray::new( self.origin + offset, self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin - offset, time, ) } }