问题二十七:ray traing中的positionable camera

198 篇文章 12 订阅
195 篇文章 27 订阅

27.1 引入张角theta和宽高比值aspect

 

回忆一下,“问题十二”中有介绍这么一张图。


当时是这么说的:已知Z=-1平面上四点的坐标,我们可以求出下面三个值。

       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);

然后,光线和平面的交点坐标可以表示为向量:lower_left_corner + u*horizontal + v*vertical。这个即为光线的方向向量。

 

现在引入一个张角theta,和画面宽高比值aspect(这个是已知的)来表示上面三个值。


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

引入张角theta,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);

(上面“-1.0”表示图像是画在Z=-1平面)

 

在运算时,theta一般用的是弧度,而我们在给函数设置参数时使用角度更为方便。所以,引入角度vfov=theta*180/M_PI(即,theta = vfov * M_PI/180)。ofov有个专业的名称:fieldof view

 

27.2 相机/眼睛/(光线起点)不在原点

先看看,在原点时,我们是怎么表示的。

坐标系的标准正交基e1 = (1, 0, 0), e2 = (0, 1, 0), e3 = (0, 0, 1)

空间中所有向量(xyz)都可以表示为:x e1+ye2+ze3

图像是画在- e3平面(即z = -1)。

lower_left_corner= origin - half_width*e1 - half_height*e2 - e3   

horizontal = 2*half_width*e1

vertical = 2*half_height*e2 

(这里的origin是原点(000))

 

对于任意观测点,我们称:

放相机的位置为lookfrom

我们看的点(画面中心点)为lookat

相机的倾斜方向为view up (简称vup,一般设置为(0,1,0))

 

有了这三个东东,我们现在就要找出相机在任意点的标准正交基(也就是相机要建立自己的坐标系,然后在自己的坐标系看之前坐标系的物体)。

w = unit_vector(lookfrom - lookat)(w相当于z)

u = unit_vector(cross(vup, w))(u相当于x)

v = cross(w, u)(v相当于y)

 

w为什么相当于z?这个是由放相机的位置(lookfrom)和目标点(lookat)确定的。

u为什么相当于x?因为相机倾斜方向vup和y比较接近,所以vup和w叉乘之后就是x。

v为什么相当于y?z、x都确定了,还有的选么?另外,w和u的叉乘相当于z、x的叉乘,结果也是y哈。

 

原坐标系中(x,y,z)对应的标准正交基是e1 , e2 , e3 

所以,

w对应e3

u对应e1

v对应e2

 

之前:

lower_left_corner= origin - half_width*e1 - half_height*e2 - e3   

horizontal = 2*half_width*e1

vertical = 2*half_height*e2 

所以,现在:

lower_left_corner= origin - half_width*u - half_height*v - w   

horizontal = 2*half_width*u

vertical = 2*half_height*v 

注意:对新坐标系来说,所有图像都是画在-w平面上

 

由上,我们在此引入了三个参数:lookfrom,lookat, vup

加上上一节中引入的两个参数:vfov,aspect

所以,现在camera类包含了五个参数。

----------------------------------------------camera.h------------------------------------------

camera.h

#ifndef CAMERA_H
#define CAMERA_H

#include "ray.h"

class camera
{
    public:
        camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect) { // vfov is top to bottom in degrees
            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 get_ray(float s, float t) {return ray(origin, lower_left_corner + s*horizontal + t*vertical - origin);}

        vec3 lower_left_corner;
        vec3 horizontal;
        vec3 vertical;
        vec3 origin;

};

#endif // CAMERA_H

----------------------------------------------main.cpp------------------------------------------

main.cpp

        hitable *list[5];

       list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.1, 0.2,0.5)));

       list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8,0.8, 0.0)));

       list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2),0.0));

       list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5));

       list[4] = new sphere(vec3(-1,0,-1), -0.45, new dielectric(1.5));

       hitable *world = new hitable_list(list,5);

        camera cam(vec3(-2,2,1), vec3(0,0,-1),vec3(0,1,0), 90, float(nx)/float(ny));

 

如“问题二十五”中介绍,如上球在原点看是这样的:



改动的相机位置之后是这样的:(vfov = 90



vfov = 40时是这样的:



vfov = 20时是这样的:



如果去掉该图中的这个球list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5));

结果是这样的:






评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值