【Ray Tracing in One Weekend】(ch10)Positionable camera
来源:互联网 发布:python 2.7 转2.6 编辑:程序博客网 时间:2024/06/03 09:54
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时,所得图片如下:
阅读全文