现在的位置: 首页 > 综合 > 正文

glMatrixMode模式操作

2013年12月10日 ⁄ 综合 ⁄ 共 3590字 ⁄ 字号 评论关闭

一、函数简介

     glMatrixMode - 指定哪一个矩阵是当前矩阵,说白了,就是对接下来要对什么进行操作做一下说明,他有三个参数选择,可以看下文。

      一般与glLoadIdentity()一同使用,glLoadIdentity()的功能是重置当前指定的矩阵为单位矩阵。

参数:

      GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作。

      这个是对模型视景的操作,接下来的语句描绘一个以模型为基础的场景,这样来设置参数,接下来用到的就是像gluLookAt()这样的函数;

      GL_PROJECTION,对投影矩阵应用随后的矩阵操作.

      这个是投影的意思,就是要对投影相关进行操作,也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如glFrustum()或gluPerspective();

      GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.
 
使用说明:
      GL_MODELVIEW 是模型矩阵 ,GL_PROJECTION 是投影矩阵。 gluPerspective的是创建一个投影矩阵并且与当前矩阵相乘,得到的矩阵设定为当前变换,但要先通过glMatrixMode设定成投影矩阵才会得到想要的投影矩阵变换。 
  例如:
  gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f);

      glMatrixMode(GL_MODELVIEW);
  可以出来结果,反之,换位置后;
  glMatrixMode(GL_MODELVIEW);
  gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f);
  则,投影矩阵位置不正确.
 
二、具体说明
我们生活在一个三维的世界——如果要观察一个物体,我们可以:
1、从不同的位置去观察它。(视图变换)
2、移动或者旋转它,当然了,如果它只是计算机里面的物体,我们还可以放大或缩小它。(模型变换)
3、如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果。另外,我们可能只希望看到物体的一部分,而不是全部(剪裁)。(投影变换)
4、我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部。(视口变换)

OpenGL变换实际上是通过矩阵乘法来实现。无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。
OpenGL可以在最底层直接操作矩阵,不过作为初学,这样做的意义并不大。这里就不做介绍了。

1、模型变换和视图变换
从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL中,实现这两种功能甚至使用的是同样的函数。
由于模型和视图的变换通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。
glMatrixMode(GL_MODELVIEW);
通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。这也只需要一行代码:
glLoadIdentity();

然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:
glTranslate*,把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。
glRotate*,把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。
glScale*,把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。

注意我都是说“与XX相乘”,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”,这是有原因的,马上就会讲到。
假设当前矩阵为单位矩阵,然后先乘以一个表示旋转的矩阵R,再乘以一个表示移动的矩阵T,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。所以,经过变换得到的顶点坐标就是((RT)v)。由于矩阵乘法的结合率,((RT)v) = (R(Tv)),换句话说,实际上是先进行移动,然后进行旋转。即:实际变换的顺序与代码中写的顺序是相反的。由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,初学的时候需要特别注意这一点。
OpenGL之所以这样设计,是为了得到更高的效率。但在绘制复杂的三维图形时,如果每次都去考虑如何把变换倒过来,也是很痛苦的事情。这里介绍另一种思路,可以让代码看起来更自然(写出的代码其实完全一样,只是考虑问题时用的方法不同了)。
让我们想象,坐标并不是固定不变的。旋转的时候,坐标系统随着物体旋转。移动的时候,坐标系统随着物体移动。如此一来,就不需要考虑代码的顺序反转的问题了。

以上都是针对改变物体的位置和方向来介绍的。如果要改变观察点的位置,除了配合使用glRotate*和glTranslate*函数以外,还可以使用这个函数:gluLookAt。它的参数比较多,前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到 (x,y,z)的直线,它表示了观察者认为的“上”方向。


2、投影变换

投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起,坐标可以不再是-1.0到1.0了!)
OpenGL支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要:
glMatrixMode(GL_PROJECTION);
通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。
glLoadIdentity();

透视投影所产生的结果类似于照片,有近大远小的效果,比如在火车头内向前照一个铁轨的照片,两条铁轨似乎在远处相交了。
使用glFrustum函数可以将当前的可视空间设置为透视投影空间。其参数的意义如下图:
http://blog.programfan.com/upfile/200610/20061007151547.gif
声明:该图片来自www.opengl.org,该图片是《OpenGL编程指南》一书的附图,由于该书的旧版(第一版,1994年)已经流传于网络,我希望没有触及到版权问题。
也可以使用更常用的gluPerspective函数。其参数的意义如下图:
http://blog.programfan.com/upfile/200610/2006100715161.gif
声明:该图片来自www.opengl.org,该图片是《OpenGL编程指南》一书的附图,由于该书的旧版(第一版,1994年)已经流传于网络,我希望没有触及到版权问题。

正投影相当于在无限远处观察得到的结果,它只是一种理想状态。但对于计算机来说,使用正投影有可能获得更好的运行速度。
使用glOrtho函数可以将当前的可视空间设置为正投影空间。其参数的意义如下图:
http://blog.programfan.com/upfile/200610/20061007151619.gif
声明:该图片来自www.opengl.org,该图片是《OpenGL编程指南》一书的附图,由于该书的旧版(第一版,1994年)已经流传于网络,我希望没有触及到版权问题。
如果绘制的图形空间本身就是二维的,可以使用gluOrtho2D。他的使用类似于glOrgho。

3、视口变换
当一切工作已经就绪,只需要把像素绘制到屏幕上了。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整的填充整个窗口,但我们完全可以只填充一半。(即:把整个图象填充到一半的窗口内)
http://blog.programfan.com/upfile/200610/20061007151639.gif
声明:该图片来自www.opengl.org,该图片是《OpenGL编程指南》一书的附图,由于该书的旧版(第一版,1994年)已经流传于网络,我希望没有触及到版权问题。

使用glViewport来定义视口。其中前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度。

4、操作矩阵堆栈
介于是入门教程,先简单介绍一下堆栈。你可以把堆栈想象成一叠盘子。开始的时候一个盘子也没有,你可以一个一个往上放,也可以一个一个取下来。每次取下的,都是最后一次被放上去的盘子。通常,在计算机实现堆栈时,堆栈的容量是有限的,如果盘子过多,就会出错。当然,如果没有盘子了,再要求取一个盘子,也会出错。
我们在进行矩阵操作时,有可能需要先保存某个矩阵,过一段时间再恢复它。当我们需要保存时,调用glPushMatrix函数,它相当于把矩阵(相当于盘子)放到堆栈上。当需要恢复最近一次的保存时,调用glPopMatrix函数,它相当于把矩阵从堆栈上取下。OpenGL规定堆栈的容量至少可以容纳32个矩阵,某些OpenGL实现中,堆栈的容量实际上超过了32个。因此不必过于担心矩阵的容量问题。
通常,用这种先保存后恢复的措施,比先变换再逆变换要更方便,更快速。
注意:模型视图矩阵和投影矩阵都有相应的堆栈。使用glMatrixMode来指定当前操作的究竟是模型视图矩阵还是投影矩阵。

【上篇】
【下篇】

抱歉!评论已关闭.