OpenGL中矩陣堆棧的頻繁壓棧和出棧操作往往是入門時最大的門檻,也是最容易造成困惑的地方踊淳,今天我們來詳細(xì)理解一下假瞬。
要了解壓棧出棧,首先要搞清楚OpenGL的狀態(tài)機(jī)是個什么東西迂尝。OpenGL基礎(chǔ)概念中講述了狀態(tài)機(jī)的概念脱茉,本文不多做闡述,簡單來說垄开,OpenGL會記錄下我們設(shè)置的各種狀態(tài)琴许,參數(shù),開關(guān)等等溉躲,不會默認(rèn)恢復(fù)榜田。
(簡單舉例理解:)
我們打開燈的開關(guān),燈就一直亮著签财,不會自動恢復(fù)串慰。
對狀態(tài)機(jī)了解之后,結(jié)合繪圖的渲染過程唱蒸,我們知道每次繪制時邦鲫,我們會使用各種不同的參數(shù),函數(shù)神汹,打開OpenGL各種功能(例如 開啟深度測試庆捺,開啟混合呆贿,開啟正背面提出)等等嫡意,而繪制完畢我們需要手動關(guān)閉,那么同樣歼捐,存儲在棧中的矩陣也是如此氓拼。
當(dāng)我們使用模型視圖矩陣來記錄物體的基礎(chǔ)位置你画,各種變化等 時,我們往往也需要手動恢復(fù)矩陣的內(nèi)容桃漾。這就是我們經(jīng)常使用的PushMatrix
和PopMatrix
坏匪。
- 為什么需要恢復(fù)?
mv(模型視圖矩陣撬统,下文簡稱mv)是全局的适滓,每次繪制都會使用,而我們在做物體變化時都是基于單元矩陣進(jìn)行操作的(并非一定如此恋追,大多數(shù)情況凭迹,也有可能一個永遠(yuǎn)不變的物體如地板罚屋,我們就不需要壓出棧
)。每個不同的變化都有自己單獨的記錄方式嗅绸,而我們實現(xiàn)效果利用不同的變化記錄值和模型視圖矩陣叉乘脾猛,如果每次不恢復(fù),那么我們需要計算基于當(dāng)前mv(此時mv中已經(jīng)結(jié)合了本次變化的結(jié)果)和變換叉乘結(jié)果來實現(xiàn)其他變化的效果朽砰。否則其他變換則會混入本次變化尖滚,即在本次變換的基礎(chǔ)上又進(jìn)行變化,就會出現(xiàn)不可預(yù)計的結(jié)果(俗稱亂套瞧柔,鬼畜,尤其在多次變換時)睦裳。
不懂造锅?舉例:
我們有一個需求:物體進(jìn)行仿射變化,平移和旋轉(zhuǎn)廉邑,平移和旋轉(zhuǎn) 我們有兩個float來記錄平移舉例和旋轉(zhuǎn)角度哥蔚,那么
1- 繪制平移,我們用mv叉乘平移距離蛛蒙,繪制糙箍。恢復(fù)牵祟。
2- 繪制旋轉(zhuǎn)深夯,mv叉乘旋轉(zhuǎn)角度,繪制诺苹,恢復(fù)咕晋。
如果不恢復(fù)呢?
1- 繪制平移收奔,mv叉乘平移距離掌呜,繪制
2- 繪制旋轉(zhuǎn),mv(第一步叉乘平移后的結(jié)果)坪哄,叉乘旋轉(zhuǎn)
那么會是什么效果呢质蕉? 顯然,我們需要一次平移翩肌,一次旋轉(zhuǎn)模暗,而上述方法結(jié)果平移了兩次,旋轉(zhuǎn)了一次摧阅。
只是兩個變化是這個結(jié)果汰蓉,持續(xù)變換呢?結(jié)果可想而知棒卷。
總結(jié)(引用老鐵的話):
mv只有一個是全局的大家都在用顾孽,如果你某個圖形A祝钢,他要有bcdefg變化,那么 push -> mvbcdefg -> pop mv若厚,這時候物體B有個一個abc999-366的變化拦英,push -> mv * abc999-366 ->pop ->mv, A和B都是要自己的變化测秸,比如A必須要bcdefg都叉乘了才可作為A的最后的mv渲染疤估,B也是同理,你把A的mvbcdefg abc999-366給B霎冯,那就亂套了铃拇,你要的最終變化給你就行了,別人的不要管
誰的變化給誰沈撞,push pop結(jié)合就OK了
最后簡單理解一下push和pop到底干了啥(引用自OpenGL基礎(chǔ)變化綜合練習(xí)實踐總結(jié))
可以理解為慷荔,push->記錄本次變化,pop->恢復(fù)本次變化缠俺, 通俗意思就是我這次該干的干完了显晶,我收拾干凈,你們在弄你們的壹士。