OpenGL學習筆記《七》攝像機

  在上一篇寫opengl座標系統的文章中,有提到視圖空間(View Space),也能夠稱之爲攝像機空間,即從攝像機角度去觀察對象。MVP轉換矩陣中,上篇文章給了一個簡單的視圖矩陣(View Matrix)將世界空間座標轉換到視圖空間座標,即相對於攝像機的座標。spa

  opengl中實際上並無直接提供攝像機對象,咱們是根據一系列的向量運算在遊戲空間中建立了一個攝像機對象,並生成對應的視圖矩陣(View Matrix)。code

  建立一個攝像機對象,咱們須要構建對應的座標體系。首先,咱們須要知道咱們是從哪裏觀察/用攝像機拍攝,因此須要肯定一個攝像機的座標。在opengl的右手座標系下,咱們先假定攝像機座標是cameraPos=(0,0,3),即z軸正方向3個單位的位置;肯定了攝像機的位置以後,利用向量減法,咱們能夠從原點出發獲得攝像機的方向,cameraDir = vp - vo,不過咱們在這裏獲得的方向實際上是攝像機拍攝方向的反反向;orm

  獲得了攝像機方向,再利用一個世界空間內相對於原點的單位向量up=(0,1,0),使用向量叉乘,咱們能夠獲得右軸向量,cameraRight = up x cameraDir;對象

  最後,根據攝像機方向,右軸,再使用向量叉乘,咱們能夠獲得上軸向量,cameraUp = cameraDir x cameraRight;blog

  利用上述獲得的方向,右軸,上軸,咱們就能夠構建出攝像機座標系統,利用這些向量咱們能夠構造一個稱之爲LookAt的矩陣,使用這個矩陣就能夠將世界空間座標轉換爲視圖空間、攝像機空間的座標了。這個矩陣的定義以下:教程

\[LookAt = \begin{bmatrix} {\color{Red}R_x} & {\color{Red}R_y} & {\color{Red}R_z} & 0\\ {\color{Green}U_x} & {\color{Green}U_y} & {\color{Green}U_z} & 0\\ {\color{Blue}D_x} & {\color{Blue}D_y} & {\color{Blue}D_z} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 0 & 0 & -{\color{Magenta} P_x}\\ 1 & 0 & 0 & -{\color{Magenta} P_y}\\ 1 & 0 & 0 & -{\color{Magenta} P_z}\\ 1 & 0 & 0 & 1\\ \end{bmatrix}\]遊戲

  R表示右軸向量,U表示上軸向量,D表示方向向量,P則表示攝像機的位置。固然咱們以前引入的glm庫,也提供了一個直接生成lookat矩陣的方法,glm::lookAt,該方法接收三個參數,參數1爲攝像機的座標向量,參數2爲原點座標,參數3爲相對於原點的單位向量up=(0,1,0)。it

  如今咱們可使用lookAt方法,生成一個上一篇文章中獲得的視圖矩陣(View Matrix)io

view = glm::lookAt(glm::vec3(0, 0, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1.0, 0));

  注意這裏,咱們將攝像機的座標設置爲(0,0,3),而上一篇文章中咱們的視圖位置設置的是(0,0,-3)。咱們能夠這樣理解,讓世界對象往前移動三個單位,換個角度能夠認爲讓攝像機日後移動三個單位。而在咱們使用的右手座標系中,從咱們眼睛出發,咱們眼前的方向是z軸的負方向,而咱們的腦後則是z軸的正方向。因此咱們在這裏將攝像機的座標設置爲(0,0,3)。class

  在實際應用中,咱們若是想獲得豐富的攝像機效果,主要就是鏡頭的先後左右推移,視角移動。

  鏡頭的先後左右推移,咱們能夠經過修改攝像機的世界座標來達到效果,在這裏針對lookAt參數稍加調整,參數2調整爲cameraPos + cameraFront(根據向量加減法可知,這裏的cameraFront實際上是前文計算到的cameraDir的反方向),向量位置加上向量方向,以便在咱們推移過程當中攝像機都一直注視目標方向:

    switch (dir)
    {
    case CameraDir::FORWARD: // 向前
        cameraPos += cameraFront * m_moveSpeed;
        break;
    case CameraDir::BACKWARD: // 向後
        cameraPos -= cameraFront * m_moveSpeed;
        break;
    case CameraDir::LEFT: // 向左
        cameraPos -= cameraRight * m_moveSpeed;
        break;
    case CameraDir::RIGHT: // 向右
        cameraPos += cameraRight * m_moveSpeed;
        break;
    default:
        break;
    }

  先後推移是加減攝像頭方向向量乘以一個速度,左右推移則是加減攝像頭右軸向量乘以一個速度。

  而視角的移動,咱們則是調整cameraFront向量,咱們在這裏先引入歐拉角的概念,有三種歐拉角:俯仰角(Pitch)、偏航角(Yaw)和滾轉角(Roll),下圖給了直觀的表示:

 

  從圖中能夠看到,俯仰角能夠產生鏡頭上下轉換的效果,偏航角則是鏡頭的左右轉換效果,滾轉角則是翻轉效果。從圖中也能夠看到,俯仰角表現爲y軸數值變更,偏航角表現爲x軸數值的變更,滾轉角表現爲z軸數值變更。根據歐拉公式,咱們能夠基於這些角度獲得咱們的方向向量。教程中介紹的攝像機系統主要關注的是俯仰角和偏航角,因此基於這兩個歐拉角咱們能夠獲得以下的方向向量:

glm::vec3 front;
front.x = cos(_yaw) * cos(_pitch);
front.y = sin(_pitch);
front.z = sin(_yaw) * cos(_pitch);
m_cameraFront = glm::normalize(front);

  具體的推導我暫時沒看懂,主要是從俯仰角獲得x、y、z後,再根據偏航角獲得x,z,爲何還要再乘上從俯仰角獲得的x,z兩個數值

  在先後左右推移、旋轉操做以後,咱們獲得了新的攝像機座標、方向向量,在代入公式,就能獲得新的lookAt矩陣,用於將世界空間座標轉換爲攝像機空間座標。

  另外:歐拉角在使用過程當中容易觸發萬向節死鎖,致使有的時候不能旋轉到咱們須要的角度。因此,好比在cocos2dx中,是用四元數計算,來進行攝像機視角旋轉的操做。四元數沒有歐拉角那麼直觀,不過也有現成的歐拉角轉四元數的公式,下面引入一段cocos2dx引擎中的轉換代碼:

float halfRadx = CC_DEGREES_TO_RADIANS(_rotationX / 2.f), halfRady = CC_DEGREES_TO_RADIANS(_rotationY / 2.f), halfRadz = _rotationZ_X == _rotationZ_Y ? -CC_DEGREES_TO_RADIANS(_rotationZ_X / 2.f) : 0;
float
coshalfRadx = cosf(halfRadx), sinhalfRadx = sinf(halfRadx), coshalfRady = cosf(halfRady), sinhalfRady = sinf(halfRady), coshalfRadz = cosf(halfRadz), sinhalfRadz = sinf(halfRadz); _rotationQuat.x = sinhalfRadx * coshalfRady * coshalfRadz - coshalfRadx * sinhalfRady * sinhalfRadz; _rotationQuat.y = coshalfRadx * sinhalfRady * coshalfRadz + sinhalfRadx * coshalfRady * sinhalfRadz; _rotationQuat.z = coshalfRadx * coshalfRady * sinhalfRadz - sinhalfRadx * sinhalfRady * coshalfRadz; _rotationQuat.w = coshalfRadx * coshalfRady * coshalfRadz + sinhalfRadx * sinhalfRady * sinhalfRadz;

  首先須要將歐拉角由角度制轉爲弧度制,而後根據公式就能計算出四元數四個份量的值,再根據這個四元數應用到矩陣計算中,進行旋轉操做。

相關文章
相關標籤/搜索