2019年5月20日 星期一

計算Perspective camera的頂點位置

計算Perspective camera的頂點位置

前言

  最近需要計算Perspective camera的頂點位置,發現不是很好算,想一下後記起之前在做Shadow map時有算過,為了防止忘記怎麼算,在此做個紀錄。

內容

  在計算之前先來說一下一般表達Perspective camera,用C++來表達的話如下
struct PerspactiveCamera
{
  float fov;
  float aspect;
  float near;
  float far;
};

為了方便說明,所以為每個頂點編號,如下圖
Perspective camera的8個頂點

在計算頂點時必須考慮坐標系,圖中所採用左手坐標系,Z軸代表遠近,X軸為左右,Y軸為上下。頂點"0"、"1"、"2"與"3"所形成的板子稱為"近板",頂點"4"、"5"、"6"與"7"所形成的板子稱為"遠板"。

  先來計算頂點的Z值,遠板的Z值等於"far",近板的Z值等於"near",沒什麼困難,那寬度呢?像是頂點"0"到頂點"1"的長度可以從高度得來,將"0"到頂點"2"的長度乘上"aspect"就可以得到寬度,所重點擺在如何計算高度,看圖中頂點"0"、"2"、"4"與"6"所圍成的板子,在參照下圖
計算遠板與近板的高度

在圖中的紅線代表近板的半高度,綠線則是遠板的半高度,近板的半高度=near*cot(fov/2),遠板的半高度=far*cot(fov/2),半高度值會剛好等於Y值,頂點"0"的Y值就是近板的半高度,頂點"2"的Y值是近板的半高度乘上負1,遠板的Y值依此類推。

   總結的計算如下
struct Point
{
  float x;
  float y;
  float z;
};
struct PerspactiveCamera
{
  float fov;
  float aspect;
  float near;
  float far;
};
//
PerspactiveCamera camera;
//...
//
Point p0,p1,p2,p3,p4,p5,p6,p7;
//
float nearHalfHeight=camera.near*cot(camera.near/2.0f);
float nearHalfWidth=nearHalfHeight*camera.aspect;
float farHalfHeight=camera.far*cot(camera.near/2.0f);
float farHalfWidth=farHalfHeight*camera.aspect;
//
p0.x = -nearHalfWidth;
p0.y =  nearHalfHeight;
p0.z =  near;
//
p1.x =  nearHalfWidth;
p1.y =  nearHalfHeight;
p1.z =  near;
//
p2.x = -nearHalfWidth;
p2.y = -nearHalfHeight;
p2.z =  near;
//
p3.x =  nearHalfWidth;
p3.y = -nearHalfHeight;
p3.z =  near;
//
p4.x = -farHalfWidth;
p4.y =  farHalfHeight;
p4.z =  far;
//
p5.x =  farHalfWidth;
p5.y =  farHalfHeight;
p5.z =  far;
//
p6.x = -farHalfWidth;
p6.y = -farHalfHeight;
p6.z =  far;
//
p7.x =  farHalfWidth;
p7.y = -farHalfHeight;
p7.z =  far;

cot()是三角函數的"Cotangent",標準C++並不提供,如果需要自己實作可以參考Stable Cotangent

參考資料

Stable Cotangent

沒有留言:

張貼留言