基礎變換
OpenGL中設計的變換主要有以下幾種:
| 變換 | 說明 |
|---|---|
| 視圖變換 | 指定觀察者位置 |
| 模型變換 | 在場景中移動物體 |
| 模型視圖 | 描述視圖/模型變換的二元性 |
| 投影 | 改變視景體大小 和 設置它的投影方式 |
| 視口 | 偽變化,對窗口上最終輸出進行縮放 |
1.1 視圖變換
- 視圖變換是應用到場景中的第一種變換,通過物體/觀察者在Z軸上的移動,確定場景中利于觀察的位置
- 默認情況下,透視投影中的觀察者位置處于原點(0,0,0),并沿著z軸負方向看向屏幕里面,一般通過moveForward方法來調整觀察者位置,moveForward默認的朝向是-z軸,所以向屏幕里面移動傳正數值,向屏幕外即+z軸,需要傳負數值
- 引用《OpenGL 超級寶典 第5版》96頁文字:
從大局上考慮,在應用任何其他模型變換之前,必須先應用視圖變換。這句話的意思就是我們后續(xù)的其他模型變換,其實都是基于視圖變換后的新坐標進行的。
1.2 模型變換
用于操縱模型與其中特定變換,也就是把物體通過平移、旋轉、縮放的過程
- 平移:物體沿著給定的軸進行移動

截屏2020-07-17 下午4.51.35.png
- 旋轉:物體圍繞一條坐標進行旋轉

截屏2020-07-17 下午4.51.42.png
- 縮放:物體進行指定數量的放大或縮小

截屏2020-07-17 下午4.55.18.png
模型變換中,兩個變換的順序是不能交換的,交換后的矩陣相乘結果是不一致的,如下圖,交換平移和旋轉的順序,得到的結果完全不一致

2251862-4783ccd3e5041822.png
造成這種情況的根本原因,主要還是因為矩陣相乘采用的是矩陣的叉乘,而矩陣叉乘是不滿足交換律的。
與3種模型變換相對應的OpenGL方法,如圖所示,關于最后的綜合變換需要作以下說明:

2251862-f6e029a08be4b118.png
1.3 投影
投影方式分為兩種
- 透視投影:屏幕上物體與實物的比例是 < 1:1的,且有遠小近大的效果
void SetPerspective(float fFov, float fAspect, float fNear, float fFar) - 正投影:屏幕上物體與實物的比例是 = 1:1的,都是一樣大的效果
void SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)
矩陣堆棧
什么是矩陣堆棧?
OpenGL的矩陣堆棧指的就是內存中專門用來存放矩陣數據的某塊特殊區(qū)域。一般說來,矩陣堆棧常用于構造具有繼承性的模型,即由一些簡單目標構成的復雜模型。矩陣堆棧對復雜模型運動過程中的多個變換操作之間的聯(lián)系與獨立十分有利。
為什么要用矩陣堆棧呢?
- 在繪制過程中,經常發(fā)生各種各樣的變化和復雜的場景,那么我們就需要一個矩陣堆棧來管理并幫助我們實現操作,這是一個很好的數據設計結構。
- 在壓棧過程中,矩陣乘以矩陣堆棧頂部矩陣,相乘結果存儲到堆棧的頂部,那么是怎么相乘的呢?首先把它頭頂(最開始那個)拿出來跟放進去的矩陣相乘,相乘完之后再將結果放到棧頂,那么繪制過程中會有很多變化,我們不可能因為一個變化而影響到全部變化,所以為了適應
GLShaderManager變化,我們可以獲取頂部矩陣的副本(GetMatrix(M3DMatrix44f mMatrix))。因為所有矩陣操作函數如glLoadMatrix(),glMultMatrix(),glLoadIdentity()等只處理當前矩陣或堆棧頂部矩陣,這樣堆棧中下面的其它矩陣就不受影響,其特性是先進后出。需要說明的是矩陣堆棧默認深度為64 - 壓棧是為了存儲一個狀態(tài),為了不影響其他狀態(tài),所以進行壓棧
- 出棧是為了恢復一個狀態(tài),當結束例如旋轉、縮放等狀態(tài)時,就需要出?;謴椭暗臓顟B(tài),所以需要出棧并且是出棧頂位置的狀態(tài)
矩陣堆棧的使用
//類型
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
//在堆棧頂部載入一個單元矩陣
void GLMatrixStack::LoadIdentity(void);
//在堆棧頂部載?任何矩陣 //參數:4*4矩陣
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
//矩陣乘以矩陣堆棧頂部矩陣,相乘結果存儲到堆棧的頂部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
//獲取矩陣堆棧頂部的值 GetMatrix 函數
//為了適應GLShaderMananger的使?用,或者獲取頂部矩陣的副本
const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
壓棧、出棧
//將當前矩陣壓入堆棧(棧頂矩陣copy 一份到棧頂)
void GLMatrixStack::PushMatrix(void);
//將M3DMatrix44f 矩陣對象壓入當前矩陣堆棧
void PushMatrix(const M3DMatrix44f mMatrix);
//將GLFame 對象壓入矩陣對象
void PushMatrix(GLFame &frame);
//出棧(出棧指的是移除頂部的矩陣對象)
void GLMatrixStack::PopMatrix(void);
矩陣堆棧中關于入棧、相乘、出棧的流程
- 原始矩陣堆棧中,拷貝一份棧頂矩陣,壓入棧頂
- 當有變換操作時,將變換操作的矩陣與矩陣堆棧棧頂相乘,將其結果覆蓋棧頂矩陣
- 如果還有其他矩陣入棧,則繼續(xù)相乘
- 當沒有矩陣需要push,即圖形繪制完成后,需要pop棧頂矩陣
需要注意:
==> 用了幾個push,就需要pop幾個矩陣,push與pop是一一對相應的
==> 最終的矩陣堆棧仍然是最初時的矩陣堆棧

2251862-7474d25c88fac263.png
仿射變換
矩陣堆棧中有與平移、旋轉、縮放三個模型變換相對應的放射變換,可以不用通過模型變換,而是直接通過矩陣堆棧的API實現這3種變換,如下表所示

2251862-1b2bd73de257aae7.png
相對于仿射變換與模型變換,我們更傾向于使用模型,這種方式用的很少