【Ray Tracing in One Weekend】(ch10)Positionable camera
阿新 • • 發佈:2019-01-04
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時,所得圖片如下: