【Ray-Tracing In One Weekend】第10章 定义相机
【简介与代码下载】
本节在上一节的基础上定义了相机,可以定义视点、朝向等。效果如下:
代码下载:
链接:https://pan.baidu.com/s/1kh7HxWxuxhuti-Xo5OZPfQ
提取码:ak4x
【相机实现】
对于相机来说,有几个变量来确定,一个是相机的位置lookfrom,也叫eye,一个是相机朝哪里看是lookat,也叫center,一个是像机向上的角度up,比如虽然你眼睛看向一个方向,此时eye, center都确定了,但是你还可以沿着鼻子转动脑袋。这就是由up来决定的。正常的情况下我们可以定义up是向上的,也即(0, 1, 0),也可以定义成其它的。
对于相机还有个参数是长宽比率aspect,是相机视域的长与宽的比,还一个参数是角度fov,相当于你眼睛慢慢闭,角度就越来越小,看的范围就小了。
理想了相机的这么多的定义之后我们来看图:
我们现在要求出相机的局部坐标的正交基,也即其局部坐标系的UVW,W很好求,eye-center就有了。其次UP和V以及W都在同一个平面上,因此W好求,UP已知,两个求cross就得出了U,然后U再与Wcross就得到了V。
有了正交基我们就确定了相机的左、右、前方向。那么相机的视域怎么求呢,
蓝色的线就是眼睛睁多大,角度是,对于方向性的东西来说,距离是无所谓的,默认为1,因此float half_height = tan(theta / 2);而长宽比已知float half_width = aspect * half_height;。
视点的位置减去半宽*U, 半高*V就是左下角,再拉开个距离W就是视平面了。
具体代码如下:
class camera
{
public:
camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect)
{
vec3 u, v, w;
float theta = float(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 u, float v)
{
return ray(origin, unit_vector(lower_left_corner + u*horizontal + v*vertical - origin));
}
vec3 origin;
vec3 lower_left_corner;
vec3 horizontal;
vec3 vertical;
};
构造camera我们可以使用如下语句:
camera cam(vec3(-1.5f, 1.5f, 0.5f), vec3(0, 0, -1), vec3(0, 1, 0), 60, float(nx)/float(ny));