【Ray Tracing in One Weekend 超詳解】 光線追蹤1-8 自定義相機設計


 

今天,我們來學習如何設計自定義位置的相機

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

它應該是一張俯瞰圖

 

 主函數:

 

 如圖:

 

 

左邊的金屬球只反射光藍色分量,右邊的漫反射球只反射光的紅色分量

至於藍色的金屬球下部是黑色的,只能解釋為下部的反射光中藍色成分比較少

 

所以,過了這一節,我們的鏡頭就可以遠近上下左右調整了,屏幕也隨時跟着相機動,為相機影像做投影

是不是非常激動

 

前面那張效果圖是如下設置的,球的性質改了一下,且把相機拉近了些(感覺書上的距離太遠了)

 

感謝您的閱讀,生活愉快~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM