【Ray Tracing in One Weekend】(ch10)Positionable camera

Chapter 10: Positionable camera

我们之前的 Camera 是被固定的,放在坐标原点的,写死的 Camera,现在我们要做一个可以随意改变位置的 Camera。

先来回忆一下之前是如何表示 Camera 的:

这里写图片描述

从一点(origin),看向一个平面(z=-1),同时用u、v乘以两个向量(horizontal、vertical),并以左下角(lower_left_corner)为原点来定位平面上任一点,Ray 就由这几个参数来确定:

Ray getRay(float u, float v) 
{
    return Ray(origin, lower_left_corner + u*horizontal + v*vertical - origin);
}

当时定义:

vec3 lower_left_corner(-2.0, -1.0, -1.0);

vec3 horizontal(4.0, 0.0, 0.0);

vec3 vertical(0.0, 2.0, 0.0);

现在,我们要为 Camera 定义新的参数来表示上面的值,首先引入张角 theta 和画面宽高比 aspect:

这里写图片描述

设整个画面的高为 height,则半高为 half_height,宽为 width,半宽为 half_width。

则有:

half_height = tan(theta/2);

half_width = aspect * half_height;


vec3 lower_left_corner(-half_width, -half_height,-1.0);

vec3 horizontal(2*half_width, 0.0, 0.0);

vec3 vertical(0.0, 2*half_height, 0.0);

现在我们仅仅是用新的参数 theta 和 aspect 表示了原来的 Camera,现在想把 Camera 架设到任意位置上,还需要引入 lookfrom(相机位置),lookat(相机看向的点),以及view of up(即表示相机正上的向量)。

可以先确定一个最容易理解的:

origin = lookfrom;

接着看看我们还需要什么来确定画面所在的“平面”,我们还需要一个指向相机正前方的向量,以确定平面的位置:

w = unit_vector(lookfrom - lookat);

垂直于 w 与 view of up(简写为vup)的向量即为“平面上”横向的向量,垂直于横向向量与 w 的向量即为竖向向量。

u = unit_vector(cross(vup, w));
v = cross(w, u);

综上,可由此五个参数,确定如下四个值:

origin = lookfrom;
lower_left_corner = origin - half_width*u - half_height*v - w;
horizontal = 2 * half_width*u;
vertical = 2 * half_height*v;

如此一来,新的 Camera 类就写好啦~ 代码如下:

#pragma once
#define _USE_MATH_DEFINES
#include "Ray.h"
#include <math.h>

class Camera 
{
public:
    //vfov: top to bottom in degrees
    Camera(Vec3 lookfrom, Vec3 lookat, Vec3 vup, float vfov, float aspect)
    {
        Vec3 u, v, w;
        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*u - half_height*v - w;
        horizontal = 2 * half_width*u;
        vertical = 2 * half_height*v;
    }

    Ray getRay(float u, float v) 
    {
        return Ray(origin, lower_left_corner + u*horizontal + v*vertical - origin);
    }

    Vec3 lower_left_corner;
    Vec3 origin;
    Vec3 horizontal;
    Vec3 vertical;
};

同时修改main方法:

    Hitable *list[5];
    list[0] = new Sphere(Vec3(0.0f, 0.0f, -1.0f), 0.5f, new Lambertian(Vec3(0.8f, 0.3f, 0.3f)));
    list[1] = new Sphere(Vec3(0.0f, -100.5f, -1.0f), 100.0f, new Lambertian(Vec3(0.8f, 0.8f, 0.0f)));
    list[2] = new Sphere(Vec3(1.0f, 0.0f, -1.0f), 0.5f, new Metal(Vec3(0.8f, 0.6f, 0.2f), 0.3f));
    list[3] = new Sphere(Vec3(-1.0f, 0.0f, -1.0f), 0.5f, new Dielectric(1.5f));
    list[4] = new Sphere(Vec3(-1.0f, 0.0f, -1.0f), 0.5f, new Dielectric(1.5f));
    Hitable *world = new HitableList(list, 5);

    Camera cam(Vec3(-2.0f,2.0f,1.0f), Vec3(0.0f,0.0f,-1.0f), Vec3(0.0f,1.0f,0.0f), 90, float(nx)/float(ny));

fov为90时,所得图片如下:

这里写图片描述

fov为40时,所得图片如下:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值