OpenGL基礎14:攝像機

 

很可惜,openGL沒有攝像機的概念

一、攝像機

我們當然需要想辦法模擬出一個攝像機,也就是玩家的視角,在前面這一章:第一個正方體,我們僅將“攝像機”往z軸正方向移動了3個單位,並且正對着(0, 0, 0),但是大部分的情況下,類似於我們處於一個3D場景中,攝像機的視角都是從上斜向下的,這個時候若想要計算攝像機的位置和方向信息,就是需要一定的運算了

既然攝像機如此重要,我們當然需要知道它的很多信息,包括:

  1. 攝像機位置
  2. 觀察方向(攝像機z軸)
  3. 垂直於觀察方向,指向攝像機右側的向量(攝像機x軸)
  4. 垂直於觀察方向,指向攝像機正上方的向量(攝像機y軸)

對於①:必定是你來確定,又或者由輸入確定(通過移動鼠標調整視角等),對於②:只要將攝像機的座標減去焦點的座標就可以了,在遊戲中,這個焦點往往是玩家自己的世界座標,而這裏我們就當作是原點(經過如此計算得出來的這個向量理論是攝像機z軸的負方向

glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);

對於③④,如果你對施密特正交化比較瞭解,那麼應該就很容易通過公式得出對應的向量,不瞭解也沒有關係,想要得到③的向量,我們只需要將y軸正方向向量(0, 1, 0)和攝像機z軸向量叉乘就可以,這個向量必定同時垂直於前兩者,至於是x軸正方向還是負方向取決與叉乘的順序,可以用右手定則得出,④同理

glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); 
glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);

 

二、LookAt矩陣

有了上面的所有信息後,我們就可以計算出攝像機的觀察矩陣了

可以發現,上面的②③④向量相互垂直,它們構成了一個全新的向量空間,這樣的話,我們只需要再有一個平移向量就可以輕鬆的創建一個矩陣,後面對於每一個頂點,我們只需要用這個矩陣乘以它就能將其變換到對應觀察空間,這便是LootAt矩陣

\operatorname{Look} A t=\left[\begin{array}{cccc} R_{x} & R_{y} & R_{z} & 0 \\ U_{x} & U_{y} & U_{z} & 0 \\ D_{x} & D_{y} & D_{z} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right] *\left[\begin{array}{cccc} 1 & 0 & 0 & -P_{x} \\ 0 & 1 & 0 & -P_{y} \\ 0 & 0 & 1 & -P_{z} \\ 0 & 0 & 0 & 1 \end{array}\right]

其中 R 爲右向量,U 爲上向量,D 爲方向向量,P 爲攝像機位置向量

  • 對於位置向量要取反,這個在上一章也提到過,因爲我們文中講述的都是攝像機的相對位置,而我們實際需要操作的卻是物體的相對位置
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));

用如上的方法,就可以直接創建一個LookAt矩陣,其中傳入的第一個參數爲攝像機位置,第二個參數爲目標位置,第三個參數爲你所描述的世界空間的上向量(就是上面的(0, 1, 0)了)

 

三、測試

上一章我們通過讓箱子自轉來讓我們能看到箱子所有的六個面,現在我們可以嘗試讓攝像機圍繞着箱子轉:

相對上一章的代碼,改動如下:

glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(57.0f), glm::vec3(-0.5f, 1.0f, 0.0f));
view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
projection = glm::perspective(glm::radians(45.0f), (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
GLint modelLoc = glGetUniformLocation(shaderYellow.Program, "model");
GLint viewLoc = glGetUniformLocation(shaderYellow.Program, "view");
GLint projLoc = glGetUniformLocation(shaderYellow.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

看上去貌似沒有什麼區別,但是這個物體其實是靜止的,是我們觀察者的位置在改變

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章