學習書籍: OpenGL 超級寶典(中文第五版) 密碼:fu4w
書籍原始碼:OpenGL 超級寶典第五版原始碼 密碼:oyb4
環境搭建:OpenGL 學習 01 - Mac 搭建 OpenGL 環境
PS:因為以後 Demo 原始碼程式碼量會越來越多,不太可能全部複製在這裡了,我就解釋下Demo 的核心原始碼,全部原始碼請前往我的 github/OpenGLDemo 下載,原始碼裡會有詳細註釋。
基本概念
一、向量
一個頂點是 XYZ 空間座標系的一個位置(x,y,z),這一個座標也能表示一個向量,是從座標原點指向這個位置點的一個向量(帶箭頭的線段)。
在 OpenGL 裡,對應資料型別為 M3DVector3f(3維浮點向量)
、M3DVector4f(4維浮點向量)
向量之間計算的幾何意義看下圖:
二、矩陣
矩陣是一種功能非常強大的數學工具,大大簡化了求解變數之間有複雜關係的方程或方程組的過程。
在 OpenGL 裡,主要運用於座標變換,對應資料型別有M3DMatrix33f(3x3浮點矩陣)
、M3DMatrix44f(4x4浮點矩陣)
等。
注意:矩陣的乘法是不滿足交換律的,即 AB != BA
三、變換
1. 檢視變換
檢視變換是應用到場景的第一種變換,用於確定場景中的有利位置,即觀察者的位置,就像在場景中放置照相機並讓它指向某個方向。
2. 模型變換
物體本身的座標變換,有旋轉、平移、縮放3種基礎模型變換。
3. 模型檢視變換
實際上就是檢視變換和模型變換的結合,因為檢視變換和模型變換實質上是一樣的,只是為了程式設計師方便而區分出來,因為你移動物體向前10m,和觀察者向後移動10m,最終效果是一樣的。
4. 投影變換
投影變換有正投影和透視投影:
- 正投影(平行投影):無論物體有多遠,都會按照同樣大小進行繪製。
- 透視投影:遠處的物體看起來會比近處同樣大小的物體更小一些。
5. 視口變換
將邏輯視窗座標對映到物理視窗座標的變換,稱為視口變換,通常我們不需要為這事操心,圖形硬體已經為我們做好了這些。
原始碼解析
一、矩陣變換
// 載入單位矩陣
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);
複製程式碼
二、投影矩陣
設定投影矩陣是通過視景體(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);
複製程式碼
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);
複製程式碼
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();
}
複製程式碼
上面的 Demo 原始碼全部都放在我的 github/OpenGLDemo 上,大家可以去下載和除錯。
有什麼問題可以在下方評論區提出,寫得不好可以提出你的意見,我會合理採納的,O(∩_∩)O哈哈~,求關注求贊