OpenGL之glMatrixMode函数的用法
函數原型:
?????? void glMatrixMode(GLenum mode)
參數說明:
?????? mode 指定哪一個矩陣堆棧是下一個矩陣操作的目標,可選值:
- GL_MODELVIEW,對模型視圖矩陣堆棧應用隨后的矩陣操作。可以在執行此命令后,輸出自己的物體圖形了。
- GL_PROJECTION,對投影矩陣堆棧應用隨后的矩陣操作。可以在執行此命令后,為我們的場景增加透視。
- GL_TEXTURE,對紋理矩陣堆棧應用隨后的矩陣操作。可以在執行此命令后,為我們的圖形增加紋理貼圖。
????? 在每個矩陣模式下都有一個矩陣堆棧,在GL_MODELVIEW模式中,堆棧深度至少為32;在GL_PROJECTION和GL_TEXTURE模式中,堆棧深度至少為2;在任何模式中,當前矩陣總是該模式下矩陣堆棧中的最頂層矩陣。
函數說明:
?????? glMatrixMode()命令將當前矩陣設置成參數所指定的模式,以滿足不同繪圖所需執行的矩陣變換。一般而言,在需要繪制出對象或要對所繪制對象進行幾何變換時,需要將變換矩陣設置成模型視圖模式;而當需要對繪制的對象設置某種投影方式時,則需要將變換矩陣設置成投影模式;只有在進行紋理映射時,才需要將變換矩陣設置成紋理模式。
????? 與glLoadIdentity()一同使用,glLoadIdentity()功能是重置當前指定的矩陣為單位矩陣。
? ? ? ?我們生活在一個三維的世界——如果要觀察一個物體,我們可以:
1、從不同的位置去觀察它。(視圖變換)
2、移動或者旋轉它,當然了,如果它只是計算機里面的物體,我們還可以放大或縮小它。(模型變換)
3、如果把物體畫下來,我們可以選擇:是否需要一種“近大遠小”的透視效果。另外,我們可能只希望看到物體的一部分,而不是全部(剪裁)。(投影變換)
4、我們可能希望把整個看到的圖形畫下來,但它只占據紙張的一部分,而不是全部。(視口變換)
這些,都可以在OpenGL中實現。
? ? ? ?OpenGL變換實際上是通過矩陣乘法來實現。無論是移動、旋轉還是縮放大小,都是通過在當前矩陣的基礎上乘以一個新的矩陣來達到目的。OpenGL可以在最底層直接操作矩陣,不過作為初學,這樣做的意義并不大。這里就不做介紹了。
一、模型變換和視圖變換? ? ? ?從“相對移動”的觀點來看,改變觀察點的位置與方向和改變物體本身的位置與方向具有等效性。在OpenGL中,實現這兩種功能甚至使用的是同樣的函數。
? ? ? ?由于模型和視圖的變換都通過矩陣運算來實現,在進行變換前,應先設置當前操作的矩陣為“模型視圖矩陣”。設置的方法是以GL_MODELVIEW為參數調用glMatrixMode函數,像這樣:
glMatrixMode(GL_MODELVIEW); //需要修改的是模型視圖矩陣、投影矩陣還是紋理矩陣。mode的值可以為:GL_MODELVIEW、GL_PROJECTION或GL_TEXTURE。 ? ? ? ?通常,我們需要在進行變換前把當前矩陣設置為單位矩陣。這也只需要一行代碼:glLoadIdentity(); ? ? ? ?然后,就可以進行模型變換和視圖變換了。進行模型和視圖變換,主要涉及到三個函數:
? ? ? ?假設當前矩陣為單位矩陣,然后先乘以一個表示旋轉的矩陣R,再乘以一個表示移動的矩陣T,最后得到的矩陣再乘上每一個頂點的坐標矩陣v。所以,經過變換得到的頂點坐標就是((RT)v)。由于矩陣乘法的結合率,((RT)v) = (R(Tv)),換句話說,實際上是先進行移動,然后進行旋轉。即:實際變換的順序與代碼中寫的順序是相反的。由于“先移動后旋轉”和“先旋轉后移動”得到的結果很可能不同,初學的時候需要特別注意這一點。
? ? ? ?OpenGL之所以這樣設計,是為了得到更高的效率。但在繪制復雜的三維圖形時,如果每次都去考慮如何把變換倒過來,也是很痛苦的事情。這里介紹另一種思路,可以讓代碼看起來更自然(寫出的代碼其實完全一樣,只是考慮問題時用的方法不同了)。
? ? ? ?讓我們想象,坐標并不是固定不變的。旋轉的時候,坐標系統隨著物體旋轉。移動的時候,坐標系統隨著物體移動。如此一來,就不需要考慮代碼的順序反轉的問題了。
? ? ? ?以上都是針對改變物體的位置和方向來介紹的。如果要改變觀察點的位置,除了配合使用glRotate*和glTranslate*函數以外,還可以使用這個函數:gluLookAt。它的參數比較多,前三個參數表示了觀察點的位置,中間三個參數表示了觀察目標的位置,最后三個參數代表從(0,0,0)到 (x,y,z)的直線,它表示了觀察者認為的“上”方向。
二、投影變換? ? ? ?投影變換就是定義一個可視空間,可視空間以外的物體不會被繪制到屏幕上。(注意,從現在起,坐標可以不再是-1.0到1.0了!)
? ? ? ?OpenGL支持兩種類型的投影變換,即透視投影和正交投影。投影也是使用矩陣來實現的。如果需要操作投影矩陣,需要以GL_PROJECTION為參數調用glMatrixMode函數。
glMatrixMode(GL_PROJECTION); ? ? ? ?通常,我們需要在進行變換前把當前矩陣設置為單位矩陣。
glLoadIdentity(); ? ? ? ?透視投影所產生的結果類似于照片,有近大遠小的效果,比如在火車頭內向前照一個鐵軌的照片,兩條鐵軌似乎在遠處相交了。
1.使用glFrustum函數可以將當前的可視空間設置為透視投影空間。其參數的意義如下圖:
? ? ? ?這個函數原型為:
void glFrustum(GLdouble left, GLdouble Right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); ? ? ? ?創建一個透視型的視景體。其操作是創建一個透視投影的矩陣,并且用這個矩陣乘以當前矩陣。這個函數的參數只定義近裁剪平面的左下角點和右上角點的三維空間坐標,即(left,bottom,-near)和(right,top,-near);最后一個參數far是遠裁剪平面的離視點的距離值,其左下角點和右上角點空間坐標由函數根據透視投影原理自動生成。near和far表示離視點的遠近,它們總為正值(near/far 必須>0)。
2.也可以使用更常用的gluPerspective函數
void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar); 創建一個對稱的透視型視景體,但它的參數定義于前面的不同,如圖。其操作是創建一個對稱的透視投影矩陣,并且用這個矩陣乘以當前矩陣。參數fovy定義視野在Y-Z平面的角度,范圍是[0.0, 180.0];參數aspect是投影平面寬度與高度的比率;參數Near和Far分別是近遠裁剪面到視點(沿Z負軸)的距離,它們總為正值。
以上兩個函數缺省時,視點都在原點,視線沿Z軸指向負方向。
3.正交投影相當于在無限遠處觀察得到的結果,它只是一種理想狀態。但對于計算機來說,使用正交投影有可能獲得更好的運行速度。
? ? ? ?使用glOrtho函數可以將當前的可視空間設置為正投影空間,如下圖所示:
? ? ? ?這個函數的原型為:
void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) ? ? ? ?六個參數,前兩個是x軸最小坐標和最大坐標,中間兩個是y軸,最后兩個是z軸值。它創建一個平行視景體(就是一個長方體空間區域)。實際上這個函數的操作是創建一個正射投影矩陣,并且用這個矩陣乘以當前矩陣。其中近裁剪平面是一個矩形,矩形左下角點三維空間坐標是(left,bottom,-near),右上角點是(right,top,-near);遠裁剪平面也是一個矩形,左下角點空間坐標是(left,bottom,-far),右上角點是(right,top,-far)。
? ? ? ?注意,所有的near和far值同時為正或同時為負,值不能相同。如果沒有其他變換,正射投影的方向平行于Z軸,且視點朝向Z負軸。這意味著物體在視點前面時far和near都為負值,物體在視點后面時far和near都為正值。
? ? ? ?只有在視景體里的物體才能顯示出來。如果最后兩個值是(0,0),也就是near和far值相同了,視景體深度沒有了,整個視景體都被壓成個平面了,就會顯示不正確。
三、視口變換? ? ? ?當一切工作已經就緒,只需要把像素繪制到屏幕上了。這時候還剩最后一個問題:應該把像素繪制到窗口的哪個區域呢?通常情況下,默認是完整的填充整個窗口,但我們完全可以只填充一半。(即:把整個圖象填充到一半的窗口內)
運用相機模擬方式,我們很容易理解視口變換就是類似于照片的放大與縮小。在計算機圖形學中,它的定義是將經過幾何變換、投影變換和裁剪變換后的物體顯示于屏幕窗口內指定的區域內,這個區域通常為矩形,稱為視口。
? ? ? ?在實際中,視口的長寬比率總是等于視景體裁剪面的長寬比率。如果兩個比率不相等,那么投影后的圖像顯示于視口內時會發生變形,如圖所示。
?
? ? ? ?使用glViewport來定義視口。其中前兩個參數定義了視口的左下腳(0,0表示最左下方),后兩個參數分別是寬度和高度。
void glViewport(GLint x,GLint y,GLsizei width,GLsizei height); 四、操作矩陣堆棧
? ? ? ? ?介于是入門教程,先簡單介紹一下堆棧。你可以把堆棧想象成一疊盤子。開始的時候一個盤子也沒有,你可以一個一個往上放,也可以一個一個取下來。每次取下的,都是最后一次被放上去的盤子。通常,在計算機實現堆棧時,堆棧的容量是有限的,如果盤子過多,就會出錯。當然,如果沒有盤子了,再要求取一個盤子,也會出錯。
? ? ? ? 我們在進行矩陣操作時,有可能需要先保存某個矩陣,過一段時間再恢復它。當我們需要保存時,調用glPushMatrix函數,它相當于把矩陣(相當于盤子)放到堆棧上。當需要恢復最近一次的保存時,調用glPopMatrix函數,它相當于把矩陣從堆棧上取下。OpenGL規定堆棧的容量至少可以容納32個矩陣,某些OpenGL實現中,堆棧的容量實際上超過了32個。因此不必過于擔心矩陣的容量問題。通常,用這種先保存后恢復的措施,比先變換再逆變換要更方便,更快速。
? ? ? ?注意:模型視圖矩陣和投影矩陣都有相應的堆棧。使用glMatrixMode來指定當前操作的究竟是模型視圖矩陣還是投影矩陣。
參考鏈接:https://blog.csdn.net/timidsmile/article/details/7016755
總結
以上是生活随笔為你收集整理的OpenGL之glMatrixMode函数的用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 函数指针及其定义和用法,C++函数指针详
- 下一篇: 英语单词 factor cull