锅炉信息网 > 锅炉知识 > 锅炉资讯

14 相机

目标完善相机类,支持视野(fov),位置,朝向和散焦模糊。第八版渲染器结构如下:光源:无。场景:地面,一个漫反射材质的球,一个金属球,一个中空玻

目标

完善相机类,支持视野(fov),位置,朝向和散焦模糊。第八版渲染器结构如下:

  • 光源:无。
  • 场景:地面,一个漫反射材质的球,一个金属球,一个中空玻璃球。
  • 摄像机:参数可调。
  • 光线:每像素16个。
  • 渲染算法:光线多次弹射,颜色依据物体材质计算。
  • 输出:400 * 225像素的无锯齿图像。

数学模型

视野

  • 视野指一个镜头能覆盖的范围,用角度来表示。
  • 根据视野和焦距,可以求出视窗大小。

位置和朝向

  • 相机的位置和朝向决定了如何将相机坐标变换到世界坐标系中。
  • 相机坐标系的原点映射到世界坐标系的相机位置(lookfrom)。
  • 相加坐标系的z轴映射到-w,也就是lookfrom - lookat
  • x轴映射到u
  • y轴映射到v
  • 一般指定一个相机朝上的大概方向vup,然后计算与wvup所在平面垂直的朝右方向u,再利用wu的叉积求出v

散焦模糊

  • 真实相机不是完美的小孔,只能清晰成像景深范围内的物体。
  • 渲染器的镜头是完美的小孔,需要模拟镜头模糊效果。

计算模型

  • 添加新参数到Camera类。
  • 修改坐标变换
  • 光线起点做随机偏移,模拟焦散。

代码

camera.rs

  1. 根据fov和焦距求出视窗尺寸
  2. 求出uvw向量
  3. 将相机坐标系映射到世界坐标系下。
  4. 在光圈范围内随机一个发射点,从这里发射光线到成像平面

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

设置参数

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

运行结果

挑战

  • 修改main.rs中的camera参数,观察运行结果的变化
  • 修改第4章的矩阵,加入相机的位置和朝向。

延伸阅读

《Ray Tracing in One Weekend》11

《Ray Tracing in One Weekend》 12

上一篇:14线

下一篇:漂亮的矿物14

锅炉资讯

锅炉资讯

锅炉学习

锅炉学习

锅炉视频

锅炉视频

锅炉百科

锅炉百科