OpenGL变换顺序的理解

来源:互联网 发布:数据库语句大全 编辑:程序博客网 时间:2024/04/28 23:39

该文转自百度空间Rocky的避风港,原文链接:

http://hi.baidu.com/rocky_ly/item/21225b271a3f4d14087508c2

关于变换操作顺序的问题

在OpenGL书籍当中,讨论变换操作时都会涉及到函数调用的顺序问题。大体有两种说法:

一种是:

          正向顺序;

              即是函数调用顺序和预想的操作顺序是相同的,变换结果同预想的结果相同。

          逆向顺序:

              即是函数调用顺序应该和预想的操作顺序是相反的,这样变换的结果才能和预想的结果相同。

看起来这两种说法截然相反,实则不然

如何建立关联而使这两种观点统一化呢?

如果将两种观点建立在不同的参考系下,分别讨论其意义,然后再讨论两种参考系的关系,就可以将两种观点统一起来,其实在进行编程的过程中,运用那种观点来指导编程都是可以的,看对那种观点掌握的更好,使用得更得心应手吧!

一、首先讨论第二种逆向顺序的观点,为什么呢?因为绝大多数书籍资料都支持这个观点,把OpenGL中的函数提供的矩阵运算视为逆向于预想顺序,而且这种观点因为其建立在最容易理解的坐标系统下,却看起来最不容易理解,所以先行讨论之!

三维图形即立体图形,只要是立体的都应该对应存在三个维,即x,y,z三个坐标轴,这三个坐标轴构成的坐标系成为笛卡尔坐标系。在三维图形学研究中,笛卡尔坐标系是重要的工具。

在OpenGL编程过程中,我们希望我们绘制的模型按照我们的规划出现在视觉坐标系的指定位置,恰好OpenGL系统中的笛卡尔坐标系可以被我们利用来在其中安排模型。于是,一些变换的操作我们很自然的希望可以在这个坐标系中看到直接的效果,即变换的过程和结果都是以这个坐标系为参照的。

无论是平移、旋转还是缩放,我们都直接以视觉坐标系作为参考。

按照平移、旋转和缩放这些操作的规定,我们在编写程序时希望通过组合这些操作来把模型安排在坐标系中的理想位置上。

通过平移,我们希望把模型挪动到指定坐标;

通过旋转,我们希望物体以某种角度放置;

通过缩放,我们希望物体以某种比例缩放成我们想要的大小。

可是,似乎我们还是不能直接按照我们的思维定势来设计各种变换的组合来达到我们的目的。

OpenGL系统通过矩阵运算来实现变换操作,OpenGL为我们维护了三个矩阵用来完成不同的变换操作,它们分别是:模型视图矩阵,投影矩阵和纹理矩阵。

通过把空间中的点的坐标(向量)拿来同相应的变换矩阵进行相乘操作,来实现变换操作,从而将向量转换成同视觉坐标相符的向量。拿模型视图矩阵举例:

现在,我们想对点v进行三次变换操作,分别是A,B,C。对应的变换矩阵分别是A,B,C。

我们的设计是:

                        变换A

                        变换B

                        变换C

                        绘制点v

对应的矩阵操作应该是:C(B(A*v))             矩阵操作是左乘的,即对应的变换矩阵要左乘顶点向量。

然而如果我们在程序中按照如下的顺序编写,结果将恰好相反

                (伪代码)

                glMutiMatrix(A);

                glMutiMatrix(B);

                glMutiMatrix(C);

                glBegin(point);

                     glVertex(v);

                glEnd();

                glFlush();

上面代码通过glMutiMatrix(A)函数将A操作对应的A矩阵乘以了当前矩阵。相应的其他矩阵也按照此规则乘以了当前矩阵,最后得到的当前矩阵是ABC,而后左乘顶点向量v得到ABCv为变换后的顶点坐标。变换效果上看,与程序中的调用顺序相反。故此,如果希望按照某种顺序对模型进行变换,需要以相反的顺序调用相应的变换函数。

二、讨论正向的观点,其实无论正向或是逆向,无非是认为函数的调用顺序同变换过程的顺序是相同还是相反,其实写同样的代码当然不可能产生两种截然相反的结果,自然同样的代码变换结果是完全相同的,那又怎么会产生两种相反的观点呢。其实,这和思考的方式是有关系的。

先来说一下正向的观点。与逆向的观点不同,持正向的观点的程序员认为,在固定的世界坐标系之外还有一个坐标系,这个坐标系是伴随着模型的变换而不断变换的,称之为模型坐标系,即模型坐标系在变换发生之前始终保持原点与模型中心重合的状态。而发生变换时,这个坐标系成为固定坐标系,一个新的模型坐标系,又跟随着模型一起移动到了新的位置。

如果这样考虑模型的变换,那么无论是函数调用顺序还是预想的变换顺序都是同向的了。

举例说明:

现在要在原点绘制一个正方体,然后先在x轴上,向正向平移5个单位,然后绕z轴逆时针旋转45度。采用逆向观点,需要在调用函数的时候,先调用旋转函数后调用平移函数,这样实际上就是先进行的平移矩阵操作,然后进行的旋转变换矩阵的操作。这样的情况下,我们认为,正方体首先平移到x轴5的位置,然后绕z轴旋转45度。采用正向观点的时候,调用函数的顺序一样,不过是理解方法不同,先调用旋转函数,正方体绕z轴旋转45度,然后调用平移函数,这时,平移函数不再是在视觉坐标系的x轴正向将旋转后的立方体平移5个单位,而是在旋转后的模型坐标系x轴正向将立方体平移了5个单位。结果同逆向考虑时一样。

可见,无论是认为实际顺序同调用顺序是逆向的,还是认为实际顺序同调用函数的顺序是同向的,其实最终结果都是一样的,不过是理解的方式以及思考不同,采用的参照系不同而已。只要能够记得清楚,无论那种理解方式都可以,条条大路通罗马!

P.S. 在思考变换操作的过程中会出现很多令人头疼的问题,有时候我们希望我们的变换操作可以以更直观的视觉坐标系(即固定在屏幕上的坐标系)为参照,但是逆向的思维有时候并不是我们的强项。其实平移操作对于坐标系的依赖不那么强,无论我们把平移理解为是坐标系平移还是模型本身的平移,其实看起来没什么差别,正如物体远离镜头同镜头远离物体看起来是完全一样的。只不过当出现旋转操作的时候会有一些问题出现。多次不同角度的旋转,旋转和平移的综合变换,这些都会令问题显得不那么容易解决,至少不是我们想象的那么直接就可以解决的。

就举一个例子,如果想使用OpenGL做出类似CS游戏那样的视觉效果(指的是使用W,A,S,D键移动,用鼠标旋转视角),就不那么容易!网友们都在学的NeHe的OpenGL教程里给出的漫游代码,其实也没有实现这个功能。编译运行NeHe给出的代码,我们会发现我们只能朝一个方向行动,而不是始终朝着我们面对着的方向向前。就是说,旋转看起来只好像是坐在火车上的我们时不时看看窗外,火车却一直向前。

这个问题我一直在研究,刚才下载了唐明理的教程,希望可以得到一些提示!