14 相機(jī)
目標(biāo)完善相機(jī)類,支持視野(fov),位置,朝向和散焦模糊。第八版渲染器結(jié)構(gòu)如下:光源:無。場景:地面,一個(gè)漫反射材質(zhì)的球,一個(gè)金屬球,一個(gè)中空玻
目標(biāo)
完善相機(jī)類,支持視野(fov),位置,朝向和散焦模糊。第八版渲染器結(jié)構(gòu)如下:
- 光源:無。
- 場景:地面,一個(gè)漫反射材質(zhì)的球,一個(gè)金屬球,一個(gè)中空玻璃球。
- 攝像機(jī):參數(shù)可調(diào)。
- 光線:每像素16個(gè)。
- 渲染算法:光線多次彈射,顏色依據(jù)物體材質(zhì)計(jì)算。
- 輸出:400 * 225像素的無鋸齒圖像。
數(shù)學(xué)模型
視野
- 視野指一個(gè)鏡頭能覆蓋的范圍,用角度來表示。

- 根據(jù)視野和焦距,可以求出視窗大小。
位置和朝向
- 相機(jī)的位置和朝向決定了如何將相機(jī)坐標(biāo)變換到世界坐標(biāo)系中。

- 相機(jī)坐標(biāo)系的原點(diǎn)映射到世界坐標(biāo)系的相機(jī)位置(lookfrom)。
- 相加坐標(biāo)系的z軸映射到-w,也就是lookfrom - lookat
- x軸映射到u
- y軸映射到v
- 一般指定一個(gè)相機(jī)朝上的大概方向vup,然后計(jì)算與w和vup所在平面垂直的朝右方向u,再利用w和u的叉積求出v。
散焦模糊
- 真實(shí)相機(jī)不是完美的小孔,只能清晰成像景深范圍內(nèi)的物體。

- 渲染器的鏡頭是完美的小孔,需要模擬鏡頭模糊效果。

計(jì)算模型
- 添加新參數(shù)到Camera類。
- 修改坐標(biāo)變換
- 光線起點(diǎn)做隨機(jī)偏移,模擬焦散。
代碼
camera.rs
- 根據(jù)fov和焦距求出視窗尺寸
- 求出uvw向量
- 將相機(jī)坐標(biāo)系映射到世界坐標(biāo)系下。
- 在光圈范圍內(nèi)隨機(jī)一個(gè)發(fā)射點(diǎn),從這里發(fā)射光線到成像平面
use crate::math::random;nuse crate::math::ray;nuse crate::math::vector;npub struct Camera {n origin: vector::Point3,n lower_left_corner_world: vector::Point3,n horizontal: vector::Point3,n vertical: vector::Point3,n u : vector::Point3,n v : vector::Point3,n lens_radius: f64,n}nimpl Camera {n pub fn new(n look_from: vector::Point3,n look_at: vector::Point3,n vup: vector::Dir3,n vfov: f64,n aspect_ratio: f64,n aperture: f64,n focus_dist: f64,n ) -> Camera {n // 1n let theta = vfov * std::f64::consts::PI / 180.0;n let h = (theta * 0.5).tan() * focus_dist;n let viewport_height = 2.0 * h;n let viewport_width = viewport_height * aspect_ratio;n // 2 n let mut w = look_from.clone() - look_at;n w.normalize();n let mut u = vector::Vec3::cross(&vup, &w);n u.normalize();n let v = vector::Vec3::cross(&w, &u);n // 3n let horizontal = u.clone() * viewport_width;n let vertical = v.clone() * viewport_height;n let origin = look_from;n let lower_left_corner_view =n -horizontal.clone() / 2.0 - vertical.clone() / 2.0 - w * focus_dist;n let lower_left_corner_world = origin.clone() + lower_left_corner_view;n Camera {n origin: origin,n lower_left_corner_world: lower_left_corner_world,n horizontal: horizontal,n vertical: vertical,n u : u,n v : v,n lens_radius: aperture / 2.0,n }n }n pub fn get_ray(&self, s: f64, t: f64) -> ray::Ray {n // 4n let rd = Camera::random_in_unit_disk() * self.lens_radius;n let offset = self.u.clone() * rd.x() + self.v.clone() * rd.y();n let p = self.lower_left_corner_world.clone()n + self.horizontal.clone() * sn + self.vertical.clone() * t;n let dir = p - &self.origin - &offset;n ray::Ray::new(self.origin.clone() + offset, dir)n }n fn random_in_unit_disk() -> vector::Vec3 {n loop {n let p = vector::Vec3::new(n random::generate_range(-1.0, 1.0),n random::generate_range(-1.0, 1.0),n 0.0,n );n if p.length_squared() < 1.0 {n return p;n }n }n }n
main.rs
設(shè)置參數(shù)
let look_from = vector::Point3::new(3.0, 3.0, 2.0);n let look_at = vector::Point3::new(0.0, 0.0, -1.0);n let focus_dist = (look_from.clone() - &look_at).length();n let cam = camera::Camera::new(look_from, look_at, vector::Dir3::new(0.0, 1.0, 0.0), 20.0, aspect_ratio, 2.0, focus_dist);n
完整代碼
https://github.com/thomation/rePleuX/releases/tag/v0.0.8
運(yùn)行結(jié)果

挑戰(zhàn)
- 修改main.rs中的camera參數(shù),觀察運(yùn)行結(jié)果的變化
- 修改第4章的矩陣,加入相機(jī)的位置和朝向。
延伸閱讀
《Ray Tracing in One Weekend》11
《Ray Tracing in One Weekend》 12









