OpenGL 學習 07 向量 矩陣變換 投影

執著丶執念發表於2018-06-02

OpenGL 學習 07   向量 矩陣變換 投影

學習書籍: OpenGL 超級寶典(中文第五版) 密碼:fu4w

書籍原始碼:OpenGL 超級寶典第五版原始碼 密碼:oyb4

環境搭建:OpenGL 學習 01 - Mac 搭建 OpenGL 環境

PS:因為以後 Demo 原始碼程式碼量會越來越多,不太可能全部複製在這裡了,我就解釋下Demo 的核心原始碼,全部原始碼請前往我的 github/OpenGLDemo 下載,原始碼裡會有詳細註釋。

基本概念

一、向量

一個頂點是 XYZ 空間座標系的一個位置(x,y,z),這一個座標也能表示一個向量,是從座標原點指向這個位置點的一個向量(帶箭頭的線段)。

在 OpenGL 裡,對應資料型別為 M3DVector3f(3維浮點向量)M3DVector4f(4維浮點向量)

OpenGL 學習 07   向量 矩陣變換 投影

OpenGL 學習 07   向量 矩陣變換 投影

向量之間計算的幾何意義看下圖:

OpenGL 學習 07   向量 矩陣變換 投影

二、矩陣

矩陣是一種功能非常強大的數學工具,大大簡化了求解變數之間有複雜關係的方程或方程組的過程。

在 OpenGL 裡,主要運用於座標變換,對應資料型別有M3DMatrix33f(3x3浮點矩陣)M3DMatrix44f(4x4浮點矩陣)等。

OpenGL 學習 07   向量 矩陣變換 投影

OpenGL 學習 07   向量 矩陣變換 投影

OpenGL 學習 07   向量 矩陣變換 投影

注意:矩陣的乘法是不滿足交換律的,即 AB != BA

OpenGL 學習 07   向量 矩陣變換 投影

三、變換

OpenGL 學習 07   向量 矩陣變換 投影

1. 檢視變換

檢視變換是應用到場景的第一種變換,用於確定場景中的有利位置,即觀察者的位置,就像在場景中放置照相機並讓它指向某個方向。

OpenGL 學習 07   向量 矩陣變換 投影

2. 模型變換

物體本身的座標變換,有旋轉、平移、縮放3種基礎模型變換。

OpenGL 學習 07   向量 矩陣變換 投影

3. 模型檢視變換

實際上就是檢視變換和模型變換的結合,因為檢視變換和模型變換實質上是一樣的,只是為了程式設計師方便而區分出來,因為你移動物體向前10m,和觀察者向後移動10m,最終效果是一樣的。

4. 投影變換

投影變換有正投影和透視投影:

  • 正投影(平行投影):無論物體有多遠,都會按照同樣大小進行繪製。
  • 透視投影:遠處的物體看起來會比近處同樣大小的物體更小一些。

OpenGL 學習 07   向量 矩陣變換 投影

5. 視口變換

將邏輯視窗座標對映到物理視窗座標的變換,稱為視口變換,通常我們不需要為這事操心,圖形硬體已經為我們做好了這些。

OpenGL 學習 07   向量 矩陣變換 投影

OpenGL 學習 07   向量 矩陣變換 投影

原始碼解析

一、矩陣變換

// 載入單位矩陣
void m3dLoadIdentity44(M3DMatrix44f m);
// 沿著 x/y/z 軸平移
void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z);
// 沿著 x/y/z 軸旋轉 angle(弧度)
void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z);
// 在 x/y/z 軸上進行縮放
void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale);
// 矩陣 a 和矩陣 b 相乘得到矩陣 product
void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const  M3DMatrix44f b);
複製程式碼

08-MoveByMatrix 核心原始碼如下,全部原始碼下載:08-MoveByMatrix

// 建立3個4x4矩陣,分別是合成矩陣、平移矩陣、旋轉矩陣
M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
// 平移(xPos, yPos, 0)的矩陣表示
m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);
// 繞z軸旋轉的矩陣,每次旋轉角度加 5 度,m3dDegToRad = 角度 -> 弧度
static float zRot = 0.0f;
zRot += 5.0f;
m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(zRot), 0.0f, 0.0f, 1.0f);
// 矩陣相乘,引數順序很重要,先平移,後旋轉
m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
複製程式碼

OpenGL 學習 07   向量 矩陣變換 投影

二、投影矩陣

設定投影矩陣是通過視景體(GLFrustum)來設定的

[GLFrustum] { // 僅僅表示以下方法是 GLFrustum 的方法
    // 設定正投影矩陣引數,(x, y, z)最小和最大值
    void SetOrthographic(GLfloat xMin, GLfloat xMax, 
                         GLfloat yMin, GLfloat yMax, 
                         GLfloat zMin, GLfloat zMax);
    // 設定透視投影矩陣引數,分別為:透視角,寬高比,近距,遠距
    void SetPerspective(float fFov, float fAspect, float fNear, float fFar);
    // 獲取投影矩陣
    const M3DMatrix44f& GetProjectionMatrix(void);
}

複製程式碼

為了方便管理各個矩陣,GLTools 提供了矩陣堆疊 GLMatrixStack,預設堆疊最大深度為 64,有壓棧、出棧等操作。

[GLMatrixStack] { // 僅僅表示以下方法是 GLMatrixStack 的方法
    // -------- 矩陣載入 -----------
    // 在棧頂載入單元矩陣,載入即覆蓋
    void LoadIdentity(void);
    // 在棧頂載入任何矩陣
    void LoadMatrix(const M3DMatrix44f m);
    // 用棧頂矩陣乘以某個矩陣,得到的結果矩陣覆蓋原來的棧頂矩陣
    void MultMatrix(const M3DMatrix44f mMatrix);
    // 獲取棧頂矩陣
    const M3DMatrix44f& GetMatrix(void);
    // -------- 出棧壓棧 -----------
    // 壓棧,在棧頂壓入一個矩陣
    void PushMatrix(const M3DMatrix44f mMatrix);
    // 出棧,把棧頂矩陣移除矩陣堆疊
    void PopMatrix(void);
    // -------- 仿射變換 -----------
    // 棧頂矩陣進行縮放變換
    void Scale(GLfloat x, GLfloat y, GLfloat z);
    // 棧頂矩陣進行平移變換
    void Translate(GLfloat x, GLfloat y, GLfloat z);
    // 棧頂矩陣進行旋轉變換
    void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
}
複製程式碼

而為了方便管理模型檢視矩陣堆疊和投影矩陣堆疊,GLTools 為我們提供了管理管線 GLGeometryTransform,幫助我們跟蹤記錄這兩種矩陣堆疊,並快速檢索模型檢視矩陣堆疊頂部或投影矩陣堆疊頂部。

[GLGeometryTransform] { // 僅僅表示以下方法是 GLGeometryTransform 的方法
    // ----------- 設定矩陣堆疊 ---------
    // 單獨設定模型檢視矩陣堆疊
    void SetModelViewMatrixStack(GLMatrixStack& mModelView);
    // 單獨設定投影矩陣堆疊
    void SetProjectionMatrixStack(GLMatrixStack& mProjection);
    // 同時設定模型檢視矩陣堆疊和投影矩陣堆疊
    void SetMatrixStacks(GLMatrixStack& mModelView, GLMatrixStack& mProjection);
    // ----------- 獲取堆疊頂部 ---------
    // 獲取模型檢視矩陣堆疊的棧頂矩陣
    const M3DMatrix44f& GetModelViewMatrix(void);
    // 獲取投影矩陣堆疊的棧頂矩陣
    const M3DMatrix44f& GetProjectionMatrix(void);
    // 獲取2個矩陣堆疊的棧頂矩陣相乘的結果矩陣
    const M3DMatrix44f& GetModelViewProjectionMatrix(void);
}
複製程式碼

10-Orthographic 核心原始碼如下,全部原始碼下載:10-Orthographic

// 設定正投影引數,(xMin, xMax, yMin, yMax, zMin, zMax)
viewFrustum.SetOrthographic(-130.0f, 130.0f, -130.0f, 130.0f, -130.0f, 130.0f);
// 獲得到的正投影矩陣載入堆疊中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 變換管線,管理2個堆疊
transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
複製程式碼

OpenGL 學習 07   向量 矩陣變換 投影

11-Perspective 核心原始碼如下,全部原始碼下載:11-Perspective

// 設定透視投影矩陣引數,分別為:透視角,寬高比,近距,遠距
viewFrustum.SetPerspective(35.0f, float(width)/float(height), 1.0f, 1000.0f);
// 載入透視投影矩陣
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 利用變換管線,管理2個堆疊
transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
複製程式碼

OpenGL 學習 07   向量 矩陣變換 投影

12-ModelViewProjection 核心原始碼如下,全部原始碼下載:12-ModelViewProjection

// 視窗渲染回撥
void RenderScene(void) {
    // 定義一個測試執行時間
    static CStopWatch rotTimer;
    // 獲取到上一個時間點到當前的時間間隔(單位是每秒刻度數,即  1/60s)
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    // 清空緩衝區
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // 定義矩陣
    M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
    // 向z軸平移的矩陣變換
    m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
    // 繞y軸旋轉的矩陣變換
    m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
    // 矩陣變換的合併矩陣
    m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
    // 投影矩陣 + 檢視變換矩陣 = 最終物體位置座標
    m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(), mModelview);
    // 繪製花托
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
    torusBatch.Draw();
    // 因為是雙緩衝區模式,後臺緩衝區替換到前臺快取區進行顯示
    glutSwapBuffers();
    // 自動觸發下次渲染回撥,達到動畫的效果
    glutPostRedisplay();
}
複製程式碼

OpenGL 學習 07   向量 矩陣變換 投影

上面的 Demo 原始碼全部都放在我的 github/OpenGLDemo 上,大家可以去下載和除錯。

有什麼問題可以在下方評論區提出,寫得不好可以提出你的意見,我會合理採納的,O(∩_∩)O哈哈~,求關注求贊

相關文章