OpenGL中矩阵堆栈的频繁压栈和出栈操作往往是入门时最大的门槛,也是最容易造成困惑的地方,今天我们来详细理解一下。
要了解压栈出栈,首先要搞清楚OpenGL的状态机是个什么东西。OpenGL基础概念中讲述了状态机的概念,本文不多做阐述,简单来说,OpenGL会记录下我们设置的各种状态,参数,开关等等,不会默认恢复。
(简单举例理解:)
我们打开灯的开关,灯就一直亮着,不会自动恢复。
对状态机了解之后,结合绘图的渲染过程,我们知道每次绘制时,我们会使用各种不同的参数,函数,打开OpenGL各种功能(例如 开启深度测试,开启混合,开启正背面提出)等等,而绘制完毕我们需要手动关闭,那么同样,存储在栈中的矩阵也是如此。
当我们使用模型视图矩阵来记录物体的基础位置,各种变化等 时,我们往往也需要手动恢复矩阵的内容。这就是我们经常使用的PushMatrix
和PopMatrix
。
- 为什么需要恢复?
mv(模型视图矩阵,下文简称mv)是全局的,每次绘制都会使用,而我们在做物体变化时都是基于单元矩阵进行操作的(并非一定如此,大多数情况,也有可能一个永远不变的物体如地板,我们就不需要压出栈
)。每个不同的变化都有自己单独的记录方式,而我们实现效果利用不同的变化记录值和模型视图矩阵叉乘,如果每次不恢复,那么我们需要计算基于当前mv(此时mv中已经结合了本次变化的结果)和变换叉乘结果来实现其他变化的效果。否则其他变换则会混入本次变化,即在本次变换的基础上又进行变化,就会出现不可预计的结果(俗称乱套,鬼畜,尤其在多次变换时)。
不懂?举例:
我们有一个需求:物体进行仿射变化,平移和旋转,平移和旋转 我们有两个float来记录平移举例和旋转角度,那么
1- 绘制平移,我们用mv叉乘平移距离,绘制。恢复。
2- 绘制旋转,mv叉乘旋转角度,绘制,恢复。
如果不恢复呢?
1- 绘制平移,mv叉乘平移距离,绘制
2- 绘制旋转,mv(第一步叉乘平移后的结果),叉乘旋转
那么会是什么效果呢? 显然,我们需要一次平移,一次旋转,而上述方法结果平移了两次,旋转了一次。
只是两个变化是这个结果,持续变换呢?结果可想而知。
总结(引用老铁的话):
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结合就OK了
最后简单理解一下push和pop到底干了啥(引用自OpenGL基础变化综合练习实践总结)
可以理解为,push->记录本次变化,pop->恢复本次变化, 通俗意思就是我这次该干的干完了,我收拾干净,你们在弄你们的。
网友评论