《Ray Tracing in One Weekend》阅读笔记 - 10、可移动的相机

    和电解质一样,相机也是一个debug的痛点。首先,我们说明一个可调节的视场(fov),这是你从入口看到的角度。由于我们的图像不是正方形,fov在水平方向和垂直方向上是不同的。作者总是用垂直fov,并且在构造函数中指定它的度数并将其转化为弧度——a matter of personal taste。

 

10.1 相机观察几何体

     一开始我们让射线从原点发出并朝向z = -1平面。我们可以让他是 z = -2平面,或者别的什么,只要能使得h于该距离成比例。这是我们的设置

    这意味着h = tan(θ/2).现在我们的camera变成了这样:

  • 初始化函数:
    • 参数:vfov  ——  垂直方向上的fov的角度
    • aspect_ratio —— 纵横比;屏幕高宽比
  • 1、将角度转化为弧度
  • 2、用h = tan(θ/2)求出h
  • 3、设置屏幕宽、高、深
  • 4、初始化类的元素
// 网页代码 camera.h - Camera with adjustable field-of-view (fov)
class camera {
    public:
        camera(
            double vfov, // vertical field-of-view in degrees
            double aspect_ratio
        ) {
            auto theta = degrees_to_radians(vfov);
            auto h = tan(theta/2);

            auto viewport_height = 2.0 * h;
            auto viewport_width = aspect_ratio * viewport_height;
            auto focal_length = 1.0;

            origin = point3(0, 0, 0);
            horizontal = vec3(viewport_width, 0.0, 0.0);
            vertical = vec3(0.0, viewport_height, 0.0);
            lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
        }

        ray get_ray(double u, double v) const {
            return ray(origin, lower_left_corner + u*horizontal + v*vertical - origin);
        }
    private:
        point3 origin;
        point3 lower_left_corner;
        vec3 horizontal;
        vec3 vertical;
};

    我们可以这样调用camera:cam(90, double(image_width)/image_height),和下面的球类:

// 网页上的代码 main.cc - Scene with wide-angle camera
auto R = cos(pi/4);
hittable_list world;
world.add(make_shared<sphere>(point3(-R,0,-1), R, make_shared<lambertian>(color(0, 0, 1))));
world.add(make_shared<sphere>(point3( R,0,-1), R, make_shared<lambertian>(color(1, 0, 0))));

    我们将得到:

vfov = 90

vfov = 75

 

 

10.2 相机的定位和定向

    为了获得任意一个视点,让我们先命名我们需要的点:

  1. lookfrom:我们放置相机的地方
  2. lookat:我们看的地方

(接下来,你也可以定义一个方向向量代替我们看的点来查看)

我们还需要一种方法来指定相机的转动或侧向倾斜:围绕lookat-lookfrom轴的旋转。  另一种思考的方法是,即使你保持lookfrom和lookat不变,你仍然可以绕着鼻子转动你的头。我们需要一种方法指定相机的“up”向量。这个up向量应该位于与视图方向垂直的平面上。

    实际上我们可以使用任何向上的向量,然后将其投影到这个平面上,就可以得到一个相机的up向量。我使用命名一个“view up(vup)向量的通用约定。做一些叉乘(cross(vup, w)、cross(w, u))可以得到u、v,现在我们有一个完整的标准正交基(uvw)来描述我们的相机的方向。

  • vup,v和w在同一个平面。
  • 注意,就像之前我们的固定相机面向-Z,我们的任意取景相机面向-w
  • 请记住:我们可以用world up(0, 1, 0)指定vup,但不是必要的。这是方便的,自然会让你的相机水平水平,直到你决定尝试疯狂的相机角度。
// 网页上的代码 [camera.h] Positionable and orientable camera
class camera {
    public:
        camera(
            point3 lookfrom,
            point3 lookat,
            vec3   vup,
            double vfov, // vertical field-of-view in degrees
            double aspect_ratio
        ) {
            auto theta = degrees_to_radians(vfov);
            auto h = tan(theta/2);
            auto viewport_height = 2.0 * h;
            auto viewport_width = aspect_ratio * viewport_height;

            auto w = unit_vector(lookfrom - lookat);
            auto u = unit_vector(cross(vup, w));
            auto v = cross(w, u);
            origin = lookfrom;
            horizontal = viewport_width * u;
            vertical = viewport_height * v;
            lower_left_corner = origin - horizontal/2 - vertical/2 - w;
        }

        ray get_ray(double s, double t) const {
            return ray(origin, lower_left_corner + s*horizontal + t*vertical - origin);
        }
    private:
        point3 origin;
        point3 lower_left_corner;
        vec3 horizontal;
        vec3 vertical;
};

这使得我们可以改变视点:

// 网页上的代码 [main.cc] Scene with alternate viewpoint
camera cam(point3(-2,2,1), point3(0,0,-1), vec3(0,1,0), 90, aspect_ratio);

我们将得到:

如果我们改变视角:

// 网页上的代码  [main.cc] Change field of view
camera cam(point3(-2,2,1), point3(0,0,-1), vup, 20, aspect_ratio);

得到的图片是:

上图玻璃球与粉球相交的地方有黑点,如果他们不相切(玻璃球半径为0.49),则没有黑点,如下图所示:

 

(原文讲得真不错,所以斜体的部分都是译过来的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值