七、OpenGL中的基礎變換和矩陣堆棧

基礎變換

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

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容