理论教育 OpenGL视图变换

OpenGL视图变换

时间:2023-11-25 理论教育 版权反馈
【摘要】:OpenGL 变换实际上是通过矩阵乘法来实现。OpenGL 可以在最底层直接操作矩阵,不过作为初学,这样做的意义并不大。在OpenGL 中,实现这两种功能甚至使用的是同样的函数。OpenGL 之所以这样设计,是为了得到更高的效率。OpenGL 支持两种类型的投影变换,即透视投影和正投影。OpenGL 规定堆栈的容量至少可以容纳32个矩阵,某些OpenGL 实现中堆栈的容量实际上超过了32个。

OpenGL视图变换

在绘制几何图形时,是否会觉得绘图的范围太狭隘了呢?坐标只能从-1 到1,还只能是X轴向右,Y轴向上,Z轴垂直屏幕。这些限制给绘图带来了很多不便。生活在一个三维的世界——如果要观察一个物体,可以:

(1)从不同的位置去观察它(视图变换)。

(2)移动或者旋转它,当然,如果它只是计算机里面的物体,还可以放大或缩小(模型变换)。

(3)如果把物体画下来,可以选择:是否需要一种“近大远小”的透视效果。另外,可能只希望看到物体的一部分,而不是全部(剪裁)(投影变换)。

(4)可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部(视口变换)。这些都可以在OpenGL 中实现。OpenGL 变换实际上是通过矩阵乘法来实现。无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。OpenGL 可以在最底层直接操作矩阵,不过作为初学,这样做的意义并不大。

1.模型变换和视图变换

从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL 中,实现这两种功能甚至使用的是同样的函数。由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以 GL_MODELVIEW 为参数调用 glMatrixMode 函数,例如,“glMatrixMode (GL_MODELVIEW);”。通常,需要在进行变换前把当前矩阵设置为单位矩阵。这只需要一行代码“glLoadIdentity();”,然后就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及3个函数:glTranslate*,把当前矩阵和一个表示移动物体的矩阵相乘,3个参数分别表示了在3个坐标上的位移值;glRotate*,把当前矩阵和一个表示旋转物体的矩阵相乘,物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle 表示旋转的角度;glScale*,把当前矩阵和一个表示缩放物体的矩阵相乘,x,y,z 分别表示在该方向上的缩放比例。注意都是说“与××相乘”,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”。假设当前矩阵为单位矩阵,然后先乘以一个表示旋转的矩阵R,再乘以一个表示移动的矩阵T,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。所以,经过变换得到的顶点坐标就是((RT)v)。由于矩阵乘法的结合率,((RT)v)=(R(Tv)),换句话说,实际上是先进行移动,然后进行旋转,即实际变换的顺序与代码中写的顺序是相反的。由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,初学的时候需要特别注意这一点。OpenGL 之所以这样设计,是为了得到更高的效率。但在绘制复杂的三维图形时,如果每次都去考虑如何把变换倒过来,也是很痛苦的事情。这里介绍另一种思路,可以让代码看起来更自然(写出的代码其实完全一样,只是考虑问题时用的方法不同了)。想象坐标并不是固定不变的。旋转的时候,坐标系统随着物体旋转。移动的时候,坐标系统随着物体移动。如此一来,就不需要考虑代码的顺序反转的问题了。以上都是针对改变物体的位置和方向来介绍的。如果要改变观察点的位置,除了配合使用glRotate*和glTranslate*函数外,还可以使用这个函数:gluLookAt。它的参数比较多,前3个参数表示了观察点的位置,中间3个参数表示了观察目标的位置,最后3个参数代表从(0,0,0)到 (x,y,z)的直线,它表示了观察者认为的“上”方向。(www.daowen.com)

2.投影变换

投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。注意,从现在起坐标可以不再是-1.0 到1.0 了。OpenGL 支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION 为参数调用glMatrixMode 函数“glMatrixMode(GL_PROJECTION);”。通常,需要在进行变换前把当前矩阵设置为单位矩阵。“glLoadIdentity();”透视投影所产生的结果类似于照片,有近大远小的效果,如在火车头内向前拍摄一个铁轨的照片,两条铁轨似乎在远处相交了。使用glFrustum函数可以将当前的可视空间设置为透视投影空间,也可以使用更常用的gluPerspective 函数。正投影相当于在无限远处观察得到的结果,它只是一种理想状态。但对于计算机来说,使用正投影有可能获得更好的运行速度。使用glOrtho 函数可以将当前的可视空间设置为正投影空间。如果绘制的图形空间本身就是二维的,可以使用gluOrtho2D。其使用类似于glOrgho。

3.视口变换

当一切工作已经就绪,只需要把像素绘制到屏幕上。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整地填充整个窗口,但完全可以只填充一半(即把整个图像填充到一半的窗口内)。使用glViewport 来定义视口,其中前两个参数定义了视口的左下角[(0,0)表示最左下方],后两个参数分别是宽度和高度。

4.操作矩阵

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

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈