今天,我們來學習如何設計自定義位置的相機
ready
我們只需要了解我們之前的坐標體系,或者說是相機位置
先看效果
Chapter10:Positionable camera
這一章我們直接用概念貫穿整章
1.fov: field of view
它是一個角度
它分為兩種:垂直方向岔開的角度(vfov)和水平方向岔開的角度(hfov)
vfov即相機在垂直方向上從屏幕頂端掃描到底部所岔開的視角角度
hfov即相機在水平方向上從屏幕左端掃描到右端所岔開的視角角度
2.aspect:屏幕寬高比
我們之前是通過直接定義屏幕的坐標位置來確定屏幕,現在,我們可以通過相機參數來確定屏幕
目前,我們暫時還用ready中的坐標,相機在原點,屏幕中心在(0,0,-1)
我們習慣采用vfov,這里我們假設一直vfov和aspect
眼睛離屏幕中心的距離為dis(也就是1)
根據 tan(vfov/2) = (屏幕高/2)/dis
得到 屏幕高 = 2 * dis * tan(vfov/2)
則,屏幕上邊界為 y_up = dis * tan(vfov/2)
屏幕下邊界為 y_bottom = - y_up
屏幕寬 = 屏幕高 * aspect
則,屏幕左邊界為 x_left = - 屏幕寬/2
屏幕右邊界為 x_right = - x_left
所以,我們目前的相機類如下:
/// camera.h // ----------------------------------------------------- // [author] lv // [begin ] 2019.1 // [brief ] the camera-class for the ray-tracing project // from the 《ray tracing in one week》 // ----------------------------------------------------- #ifndef CAMERA_H #define CAMERA_H #include "ray.h" namespace rt { class camera { public: camera(rtvar vfov, rtvar aspect) :_eye(rtvec(0.,0.,0.)) { rtvar theta = vfov * π / 180; rtvar half_height = tan(theta / 2); rtvar half_width = aspect * half_height; _start = rtvec(-half_width, -half_height, -1.0); _horizontal = rtvec(2 * half_width, 0., 0.); _vertical = rtvec(0., 2 * half_height, 0.); } inline const ray get_ray(const rtvar u,const rtvar v)const { return ray{ _eye, _start + u*_horizontal + v*_vertical }; } inline const ray get_ray(const lvgm::vec2<rtvar>& para)const { return ray{_eye, _start + para.u()*_horizontal + para.v()*_vertical}; } inline const rtvec& eye()const { return _eye; } inline const rtvec& start()const { return _start; } inline const rtvec& horizontal()const { return _horizontal; } inline const rtvec& vertical()const { return _vertical; } private: rtvec _eye; rtvec _start; //left-bottom rtvec _horizontal; rtvec _vertical; }; } #endif
同時,我們如下設置main的相關數據,先來測試一下
Lambertian(rtvec(0,0,1))過濾red和green,完全保留blue
得到如下圖:
沒問題吧,屏幕寬為4,高為2,兩邊少的部分是被視錐體切掉了
從原點往左右邊界連線,左三角面和右三角面內的部分才可見
3.lookfrom:相機所在位置
4.lookat:相機視線指向的位置點
相機在lookfrom位置看向lookat點
5.相機平面
相機平面是過lookfrom垂直於視線(from->at)的一個平面
類似於坐標系,確定平面當然也需要正交基向量,而相機三維正交基一般采用uvw坐標系
一個個描述
在闡述uvw之前先確定一個正向上的向量,因為相機坐標系算是一個局部性質的,當我們把它放在世界坐標系中,就需要用一個始終指向世界坐標系正上方的基向量vup(view up)
我們現在來確定三維正交相機坐標系
我們先來確定w,w是一個正交於相機平面的基向量
它的定義為 w = lookfrom - lookat
即:與視線反向的一個基向量
有了w,我們便可以定義u了,u向量代表相機平面的水平向量
u一定平行於世界坐標系的x軸
vup平行於世界坐標系的y軸
所以u⊥vup
而w⊥相機平面,所以w⊥u
所以 u = vup × w 該體系為右手系
最后定義v,v就是相機平面的垂直方向
即, v = w × u
所以,我們可以定義一個完整的camera類啦
構造函數改動如下:
我們試着,站在(-2,2,1)位置,往屏幕中心(0,0,-1)看
它應該是一張俯瞰圖
主函數:
如圖:
左邊的金屬球只反射光藍色分量,右邊的漫反射球只反射光的紅色分量
至於藍色的金屬球下部是黑色的,只能解釋為下部的反射光中藍色成分比較少
所以,過了這一節,我們的鏡頭就可以遠近上下左右調整了,屏幕也隨時跟着相機動,為相機影像做投影
是不是非常激動
前面那張效果圖是如下設置的,球的性質改了一下,且把相機拉近了些(感覺書上的距離太遠了)
感謝您的閱讀,生活愉快~