v4vendeta's homepage

Home | About | Contacts | Blogs| Others

Ray Tracing in One Weekend Summary VIII - Camera

相机


投影

θ是可视角度,图像的高度 h=tan(θ/2)

我们想要我们的相机处于任意位置并可以指向任意位置,即从 lookfrom指向lookat

我们要求得垂直于 lookfrom-lookat向量的平面上的单位向量 uv

已知有 vuplookfrom-lookat两个向量,求 uv向量的方式如下:

u=cross(vup,lookfrom)

v=cross(u,lookfrom)

uv是投影平面水平和竖直方向的步长


景深

关于景深的介绍笔者不再赘述,用代码模拟这种效果的基本思想如下:

关于成像位置,引入参数focus_dist之后,成像位置将会是-focus_dist*w。图片的高宽都需要乘以参数focus_dist。光线从镜头内的随机一点射出,打到焦平面上


相机类

#ifndef CAMERAH
#define CAMERAH

#include "random.h"
#include "ray.h"

vec3 random_in_unit_disk() {
    vec3 p;
    do {
        p = 2.0*vec3(random_double(),random_double(),0) - vec3(1,1,0);
    } while (dot(p,p) >= 1.0);
    return p;
}

class camera {
    public:
        camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect,
               float aperture, float focus_dist) {
            lens_radius = aperture / 2;
            float theta = vfov*M_PI/180;
            float half_height = tan(theta/2);
            float half_width = aspect * half_height;
            origin = lookfrom;
            w = unit_vector(lookfrom - lookat);
            u = unit_vector(cross(vup, w));
            v = cross(w, u);
            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;
        }

        ray get_ray(float s, float t) {
            vec3 rd = lens_radius*random_in_unit_disk();
            vec3 offset = u * rd.x() + v * rd.y();
            return ray(origin + offset,
                       lower_left_corner + s*horizontal + t*vertical
                           - origin - offset);
        }

        vec3 origin;
        vec3 lower_left_corner;
        vec3 horizontal;
        vec3 vertical;
        vec3 u, v, w;
        float lens_radius;
};
#endif

camera类的构造函数中

lookfrom:观察点

lookat:目标点,即视野中心

vup:摄像机竖直上方

vfov:可视角度

aspect:长宽比

focus_dist:焦距

aperture:光圈大小


修改main函数中下面语句

vec3 lookfrom(3,3,2);
vec3 lookat(0,0,-1);
float dist_to_focus = (lookfrom-lookat).length();
float aperture = 2.0;

camera cam(lookfrom, lookat, vec3(0,1,0), 50,
           float(nx)/float(ny), aperture, dist_to_focus);

将观察点放置在(-2,2,1),指向(0,0,-1)(中间蓝球的中心),y轴为上方,可视角度为90度…


结果如下

.. ... ...