2014-04-22 149 views
0

最近我實現了一個簡單的Opengl程序組成的對象場景,我已經應用了大部分變換&投影矩陣,在這樣的情況下,我能夠rotate transform & scale objects, move my camera through z & x coordinates and applied perspective projection然而,當涉及到相機旋轉的東西變得很奇怪,我的相機的旋轉矩陣只是一個旋轉矩陣,它可以使世界一致地旋轉,但是當我旋轉這個世界時,我會向上看; +y;當我向前移動時,相機看起來並沒有朝着它所看的方向前進; as it is the case in FPS games我的相機移動相對於世界空間,我知道,我很想念在x,y,z座標指定的方向向量,但我無法將這些向量與我的相機(視圖變換)矩陣,大部分教程互聯網上任何描述它在一個框圖或使用傳統的gluLookAt()函數,我真的需要一個關於視圖轉換,特別是相機旋轉的簡要說明,以及我應該如何在我的矩陣中實現它,我的最終矩陣如下:Opengl視圖變換矩陣旋轉

resultTransform = perspectiveTrans * cameraTrans * modelTrans;

其中:

perspectiveTrans =僅施加透視投影變換

cameraTrans =是旋轉的組合,翻譯影響所有obj.s場景中的矩陣

modelTrans =是施加到模型轉換

Matrix4X4.cpp文件:

#include "Matrix4X4.h" 

using namespace std; 


////////////////////////////////// Constructor Declerations //////////////////////////////// 

Matrix4X4::Matrix4X4() 
{ 
setIdentity(); 
} 

Matrix4X4::Matrix4X4(float value) 
{ 
for(int i = 0 ; i < 4; i++) 
    for (int j = 0; j < 4; j++) 
     Matrix[i][j] = value; 

} 

///////////////////////////////////////////////////////////////////////////////// 







////////////////////////////// Destructor Decleration ////////////////////////////// 
Matrix4X4::~Matrix4X4() 
{ 

} 

/////////////////////////////////////////////////////////////////////////////////// 







/////////////////////// Set Identity Matrix ///////////////////////////////////////// 

void Matrix4X4::setIdentity() 
{ 
Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0;  Matrix[0][3] = 0; 
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0;  Matrix[1][3] = 0; 
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1;  Matrix[2][3] = 0; 
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0;  Matrix[3][3] = 1; 


} 

/////////////////////////////////////////////////////////////////////////////////// 






///////////////////////// Set Translation Matrix ////////////////////////////////// 

Matrix4X4 Matrix4X4::setTranslation(float x,float y,float z) 
{ 


Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0;  Matrix[0][3] = x; 
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0;  Matrix[1][3] = y; 
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1;  Matrix[2][3] = z; 
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0;  Matrix[3][3] = 1; 

return *this; 

} 
///////////////////////////////////////////////////////////////////////////////// 





////////////////////////////////////// Set Rotation Matrix  /////////////////////////////////////////// 

Matrix4X4 Matrix4X4::setRotation(float x,float y,float z) 
{ 
Matrix4X4 xRot; 
Matrix4X4 yRot; 
Matrix4X4 zRot; 

x = (float)x * 3.14/ 180.0; 
y = (float)y * 3.14/ 180.0; 
z = (float)z * 3.14/ 180.0; 



xRot.Matrix[0][0] =1;   xRot.Matrix[0][1] = 0;  xRot.Matrix[0][2] = 0;   xRot.Matrix[0][3] = 0; 
xRot.Matrix[1][0] =0;   xRot.Matrix[1][1] = cosf(x); xRot.Matrix[1][2] = -sinf(x); xRot.Matrix[1][3] = 0; 
xRot.Matrix[2][0] =0;   xRot.Matrix[2][1] = sinf(x); xRot.Matrix[2][2] = cosf(x); xRot.Matrix[2][3] = 0; 
xRot.Matrix[3][0] =0;   xRot.Matrix[3][1] = 0;  xRot.Matrix[3][2] = 0;   xRot.Matrix[3][3] = 1; 

yRot.Matrix[0][0] = cosf(y); yRot.Matrix[0][1] = 0;  yRot.Matrix[0][2] = -sinf(y); yRot.Matrix[0][3] = 0; 
yRot.Matrix[1][0] =0;   yRot.Matrix[1][1] = 1;  yRot.Matrix[1][2] = 0;   yRot.Matrix[1][3] = 0; 
yRot.Matrix[2][0] = sinf(y); yRot.Matrix[2][1] = 0;  yRot.Matrix[2][2] = cosf(y); yRot.Matrix[2][3] = 0; 
yRot.Matrix[3][0] =0;   yRot.Matrix[3][1] = 0;  yRot.Matrix[3][2] = 0;   yRot.Matrix[3][3] = 1; 

zRot.Matrix[0][0] = cosf(z); zRot.Matrix[0][1] = -sinf(z); zRot.Matrix[0][2] = 0;   zRot.Matrix[0][3] = 0; 
zRot.Matrix[1][0] = sinf(z); zRot.Matrix[1][1] = cosf(z); zRot.Matrix[1][2] = 0;   zRot.Matrix[1][3] = 0; 
zRot.Matrix[2][0] =0;   zRot.Matrix[2][1] = 0;  zRot.Matrix[2][2] = 1;   zRot.Matrix[2][3] = 0; 
zRot.Matrix[3][0] =0;   zRot.Matrix[3][1] = 0;  zRot.Matrix[3][2] = 0;   zRot.Matrix[3][3] = 1; 


return (zRot * yRot * xRot) ; 

} 

//////////////////////////////////////////////////////////////////////////////////////////////////// 






//////////////////////////////////////// Set Scale Matrix ////////////////////////////////////////// 

Matrix4X4 Matrix4X4::setScale(float x,float y,float z) 
{ 


Matrix[0][0] =x; Matrix[0][1] = 0; Matrix[0][2] = 0;  Matrix[0][3] = 0; 
Matrix[1][0] =0; Matrix[1][1] = y; Matrix[1][2] = 0;  Matrix[1][3] = 0; 
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = z;  Matrix[2][3] = 0; 
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0;  Matrix[3][3] = 1; 

return *this; 
} 

///////////////////////////////////////////////////////////////////////////////////////////////////// 





///////////////////////////////// Set Perspective Projection /////////////////////////////////////// 

void Matrix4X4::setPerspective(float fov,float aRatio,float zNear,float zFar) 
{ 


fov = (fov/2) * 3.14/180.0; 
float tanHalfFOV = tanf(fov); 
float zRange = zNear - zFar; 


Matrix[0][0] =1.0f/(tanHalfFOV * aRatio); Matrix[0][1] = 0;     Matrix[0][2] = 0;       Matrix[0][3] = 0; 
Matrix[1][0] =0;        Matrix[1][1] = 1.0f/tanHalfFOV; Matrix[1][2] = 0;       Matrix[1][3] = 0; 
Matrix[2][0] =0;        Matrix[2][1] = 0;     Matrix[2][2] = (-zNear - zFar)/ zRange; Matrix[2][3] = 2* zFar * zNear/zRange; 
Matrix[3][0] =0;        Matrix[3][1] = 0;     Matrix[3][2] = 1;       Matrix[3][3] = 0; 



} 
///////////////////////////////////////////////////////////////////////////////////////////////////////// 





////////////////////////////////////// Getters & Setters //////////////////////////////////////////// 

float * Matrix4X4::getMat() 
{ 
return (float *) Matrix; 
} 


float Matrix4X4::getMember(int x, int y) const 
{ 
return Matrix[x][y]; 
} 


void Matrix4X4::setMat(int row,int col,float value) 
{ 
Matrix[row][col] = value; 
} 

///////////////////////////////////////////////////////////////////////////////////////////////////// 






/////////////////////////////////////// (*) Operator Overload ////////////////////////////////////// 

Matrix4X4 operator * (const Matrix4X4 & lhs,const Matrix4X4 & rhs) 
{ 

Matrix4X4 result; 

    for(int i = 0 ; i < 4; i++) 
     for (int j = 0; j < 4; j++) 
      result.setMat(i, j, lhs.getMember(i,0) * rhs.getMember(0, j) + 
          lhs.getMember(i,1) * rhs.getMember(1, j) + 
          lhs.getMember(i,2) * rhs.getMember(2, j) + 
          lhs.getMember(i,3) * rhs.getMember(3, j)); 


     return result; 
} 
////////////////////////////////////////////////////////////////////////////////////////////////// 

轉換代碼我在主塊使用:

 SDL_PumpEvents(); 

     for (int x = 0; x< 256; x++) 
     { 
      if (state[x] == 1) 
      { 
       if(x == 26) 
        tranForward -= 0.001; 
       if (x == 22) 
        tranForward += 0.001; 
       if (x == 4) 
        tranRight += 0.0009; 
       if (x == 7) 
        tranRight -= 0.0009; 

       if (x == 82) 
        lookUp += 0.02; 
       if (x == 81) 
        lookUp -= 0.02; 
       if (x == 80) 
        lookRight -= 0.02; 
       if (x == 79) 
        lookRight += 0.02; 
      } 
     } 





     modelTrans = Translation.setTranslation(0, 0, 5) * Scale.setScale(0.5, 0.5, 0.5); 
     camTrans = Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward); 
     Projection.setPerspective(70, win.getWidth()/win.getHeight(), 0.1, 1000); 


     result = Projection * camTrans * modelTrans; 




     glUniformMatrix4fv(uniformloc, 1, GL_TRUE, result.getMat()); 
+0

沒有看到特定的代碼,我最好的猜測是你的相機旋轉和翻譯是以錯誤的順序發生。做一個旋轉和一個翻譯與翻譯和旋轉的效果並不相同。 – user3256930

+0

@ user3256930我添加了我的矩陣類和轉換乘法代碼,我使用了帶有運算符重載的自定義矩陣類。 – BulBul

回答

2

的矩陣乘法沒有相同的規則,標量乘法和你的情況A * B不等於B *一當乘以矩陣。如果代碼的其餘部分是很好的解決方案可能只是轉向

result = Projection * camTrans * modelTrans; 

result = Projection * (modelTrans * camTrans); 

不要送花兒給人注意兩者相乘的順序並使用任何東西,但標量值打交道時,括號中。

一般來說,當你結合你需要考慮在基質自己的空間座標系中的平移和旋轉矩陣,這意味着喜歡玩FPS:

乘以rotation*translation意味着對象將首先旋轉,然後平移意味着物體位置將取決於已經應用的旋轉,180度旋轉將從第三視角透視物體向後移動。

乘以translation*rotation表示物體將首先平移然後旋轉,這意味着無論物體旋轉如何,物體實際上都會被移動到相同的方向上,只有物體所面對的方向將被旋轉矩陣改變。

只是一個很好的例子,如果你想提出圍繞太陽地球的運動(同時繞自身軸線旋轉正對一些半徑地球環繞太陽):

Matrix4X4 orbitRotation; //rotation matrix for where in orbit the object is 
    Matrix4X4 objectRotation; //object rotation around its own axis 
    Matrix4X4 orbitRadius; //object orbit radius 

    Matrix4X4 result = (orbitRotation*orbitRadius)*objectRotation; 
+0

我認爲情況並非如此,我已經嘗試了所有乘法順序的組合,但問題仍然存在,我認爲它涉及不知道向上,正面和側面向量在哪裏的相機旋轉矩陣,因此從世界空間向相機空間的轉變失敗了。 – BulBul

+0

爲什麼你在每個輸入上設置矩陣,你需要更新它。嘗試做result = result * camTrans * modelTrans;然後當你設置矩陣調用Projection *結果。同樣那些tranForward和相似的參數將被刪除,它們不能被增加,但是根據輸入(例如鼠標拖動路徑的長度)固定。 –

+0

Oblack我照你說的做了它不是有一些奇怪的行爲,並且在我按住w'(Forward)'按鈕之後對象立即消失,你有沒有任何好的示例或者在線教程涉及視圖轉換的這種旋轉,我意思是一個使用歐拉旋轉而不使用四元數的旋轉矩陣,或者至少你可以引導我通過一個簡單的代碼,任何幫助將非常感激,在此先感謝。 – BulBul

0

我的代碼似乎忽略先前矩陣計算和重新計算出的變換相對於我的場景的初始狀態,所需的世界旋轉&翻譯是通過使用旋轉&翻譯的固定值實現的,修改後的代碼塊如下:

 for (int x = 0; x< 256; x++) 
     { 
      if (state[x] == 1) 
      { 
       if(x == 26) 
        tranForward = -0.001; 
       if (x == 22) 
        tranForward = 0.001; 
       if (x == 4) 
        tranRight = 0.0009; 
       if (x == 7) 
        tranRight = -0.0009; 

       if (x == 82) 
        lookUp = 0.02; 
       if (x == 81) 
        lookUp = -0.02; 
       if (x == 80) 
        lookRight = -0.02; 
       if (x == 79) 
        lookRight = 0.02; 
      } 
     } 

camTrans = Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward); 

     result = camTrans * result; 

     modelTrans = Projection * result; 



     tranForward = 0.0; 
     tranRight = 0.0; 
     lookUp  = 0.0; 
     lookRight = 0.0; 

     glUniformMatrix4fv(uniformloc, 1, GL_TRUE, modelTrans.getMat()); 

請注意,結果矩陣會跟蹤以前的狀態,並針對它應用當前的狀態轉換。