raytracers/rtiow/src/camera.rs

88 lines
2.3 KiB
Rust

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::<f32>(0., 1.),
rng.gen_range::<f32>(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::<f32>(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,
)
}
}