一個關於座標轉換系統的講解
一、攝像機
- OpenGL本身沒有攝像機(Camera)的概念,但是我們可以通過把場景中的所有物體往相反方向移動的方式來模擬出攝像機,產生我們在移動的感覺,而不是場景在移動。
- 以攝像機的視角作爲場景原點時場景中所有的頂點座標:觀察矩陣把所有的世界座標變換爲相對於攝像機位置與方向的觀察座標。
- 要定義一個攝像機,我們需要它在世界空間中的位置、觀察方向、一個指向它右側的向量以及一個指向它上方的向量。
- 實際上創建一個三個單位軸相互垂直的、以攝像機的位置爲原點的座標系。
- 攝像機位置:世界空間中一個指向攝像機位置的向量。
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
- 攝像機方向:指 攝像機指向哪個方向。現在我們讓攝像機指向場景的原點:(0, 0, 0)。
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
2.1 此時,用場景原點向量減去攝像機位置向量的結果就是攝像機的指向方向。
2.2 由於我們知道攝像機指向z軸負方向,但是我們希望方向向量(Direction vector)指向攝像機的z軸正方向。如果我們交換相減的順序,我們就會獲得一個指向攝像機z軸正方向的向量。
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
- 右軸:右向量(Right Vector),代表攝像機空間的x軸的正方向。爲了獲取右向量我們需要先使用一個小技巧:先定義一個上向量(Up Vector)。接下來把上向量和第二步得到的方向向量進行叉乘。兩個向量叉乘的結果會同時垂直於這兩個向量,因此我們就可以得到指向x軸正方向的那個向量(注:若我們交換兩個向量叉乘的順序就會得到相反的指向x軸負方向的向量)。
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection);
- 上軸:已經有了x軸向量(cameraRight)和z軸向量(cameraDirection), 獲取一個指向攝像機的y軸正方向的向量就相對簡單,直接利用叉乘。
glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight);
二、 LookAt矩陣
- 使用矩陣的好處之一是如果你使用3個相互垂直(或非線性)的軸定義了一個座標空間,你可以用這3個軸 外加 一個平移向量 來創建一個矩陣,並且你可以用這個矩陣乘以任何的向量來將其變換到當前這個座標空間。
- 有了3個相互垂直的軸和一個定義攝像機空間的位置座標,可以創建自己的LookAt矩陣。
- LookAt矩陣:創建一個看着給定目標的觀察矩陣。
- 位置向量在矩陣中運算時是相反的,因爲我們最終希望把世界平移到與我們自身移動的相反方向。
- glm::LookAt函數需要一個位置、目標和上向量。他會創建一個和在上一節使用的一樣的觀察矩陣。
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), //攝像機的位置向量
glm::vec3(0.0f, 0.0f, 0.0f), //目標位置向量
glm::vec3(0.0f, 1.0f, 0.0f)); //上向量
- 攝像機類裏面的返回矩陣定義如下:
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
//這裏的目標位置改成了 攝像機位置 加上 上方向向量,
//glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f)
//這樣可以保證攝像機永遠注視着目標方向。
三、視角移動
- 爲了能夠改變視角,我們需要根據鼠標的輸入改變 cameraFront 向量。
- 歐拉角: 俯視角(Pitch)、偏航角(Yaw)和滾轉角(Roll)
2.1 俯視角(Pitch):往上或者往下看的角度,繞x軸。
2.2 偏航角(Yaw):往左或者往右看的程度,繞y軸。
2.3 滾轉角(Roll):如何翻轉攝像機,繞z軸。