opengl中坐标系的理解

OpenGL 中场景进行变换,要经历一些过程:视图变换 à 模型变换 à 投影变换,然后到了窗口坐标。这几个变换开始的时候把我搞很混,这几天整理一下。

       一般书上把这几个变换用照相机类比,其实每个变换都是产生着一个 4x4 矩阵,然后与当前矩阵(Current Matrix) 相乘,得到一个坐标变换矩阵,最后把世界坐标系(欧式空间)中的物体变换到屏幕坐标系中。这里梳理一下概念:

       1 、视图变换( VIEW Transformation ):它类似将照相机指向物体,即确定视点(观察点)的位置和观察方向。一般用的函数为 glu 封装的函数:

void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,  --------- 观察点

       GLdouble centrex, GLdouble centrey, GLdouble centrez,  -- 视线方向:从 eye 指向 centre

       GLdouble upx, GLdouble upy, GLdouble upz ------------ 视图体自下而上的方向

 )

       这个函数会产生一个视图矩阵,并右乘到当前矩阵上。模型变换通常发生在模型变换之前。其实,视图变换也是通过平移和旋转得到的,观察位置与物体位置之间是个相对的状态,我们也把视图变换和模型变换统一成一个变换,产生一个矩阵:模型视图变换矩阵。

       2 、模型变换 (MODEL Transformation) :它确定模型的位置和方向,对模型进行旋转、平移和缩放。用到三个子函数: glTranslate*(x, y, z) 、 glRotate*(x, y, z) 、 glScale*(x, y, z) 。每个函数都会产生一个矩阵,并右乘当前矩阵。

       3 、投影变换( PROJECTION Transformation ):产生一个六面的视图体,把视图体以外的场景剪裁掉,把视图体内的物体、场景作为绘制对象,让“照相机拍摄”。两种投影方式,两个投影函数:glFrustum(left, right, bottom, top, near, far) ,

glOrtho(left, right, bottom, top, near, far )

这两个函数的参数非常对称,都是构筑了一个六面体,形成可视范围。它们都产生一个矩阵,并左乘当前矩阵。(当然,还有 glu 的两个函数)。

      

       要理解整个过程,关键在理解当前变换矩阵 CTM ,(简称为 C )。它是一个状态概念,应用到 OpenGL流水线中的每一个定点: P = C*P’ 。这条等式是对同一个点在两个坐标系体统之间进行转换,从右边的坐标系下的坐标( P’ )转换到左边的坐标系下的坐标( P )。而矩阵 C 是 4x4 的齐次坐标矩阵,它都蕴含着一个局部坐标系信息:以右边坐标系为参考坐标系统,左边坐标系的位置和方向。

       用手工定义一个矩阵,如下(按 OpenGL 矩阵方式定义。与数学定义矩阵的方式转置):

       CTM[16] = { a0, a1, a2, a3,         // x 轴的方向向量

                        a4, a5, a6, a7,          // y 轴的方向向量

                        a8, a9, a10, a11,              // z 轴的方向向量

                        a12, a13, a14, a15    // 原点的位置

                            }

      

       再来考察当前变换矩阵 CTM ,它是在 OpenGL 流水线中一个模型视图矩阵和一个投影矩阵的复合。 CTM = P*C*M 。(注意到上面提到的左乘右乘了吗?)

我们来分析一个简单的例子: 见openGL 坐标系(2)

 

对 glRotatef(45.0, 0.0, 0.0, 1.0)   

glTranslatef(3.0, 0.0, 0.0);  

这两个变换,可以看成:

       glMultMatrixf(R);

       glMultMatrixf(T);

R,T 都是右乘到 CTM : CTM = CTM * R * T

对模型变换的理解有两种:

1、在全局固定坐标系下,对物体进行变换。这时候,我们要以相反的顺序来考虑代码中的变换函数了,它的实际过程是这样 P = CTM *( R*(T* p’)) 。

首先、对物体进行平移,平移到坐标( 3.0, 0.0, 0.0 )。  然后,把物体相对原点绕z轴旋转45度。

2、物体捆绑在局部坐标系下,所有的变换都是坐标系进行的。这时,我们用顺序来看这个变换。

glRotatef(45.0, 0.0, 0.0, 1.0) 产生一个齐次矩阵 R( 这可是代表一个局部坐标系哦 )   ,即局部坐标系 R 相对刚才开始的坐标系 I (单位矩阵)作了旋转变换,绕旋转了45度。

glTranslatef(3.0, 0.0, 0.0) 产生一个齐次矩阵 T (也是代表了一个局部坐标系),相对 R 坐标系沿x轴( R 系)平移了3个单位,得到了自己的局部坐标系 T 。

最后在这个局部坐标系 T 下画了 Cube 。

代码中的 Tmat = R * T ,它也是从 T 坐标系变换到 R 坐标系,再变换到最后的模型视图的世界坐标系。


openGL使用右手坐标

从左到右,x递增
从下到上,y递增
从远到近,z递增


--------------------------------------------------------------------------------

 

OPENGL坐标系可分为:世界坐标系和当前绘图坐标系。

世界坐标系以屏幕中心为原点(0, 0, 0)。你面对屏幕,你的右边是x正轴,上面是y正轴,屏幕指向你的为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1)。

当前绘图坐标系是 绘制物体时的坐标系。程序刚初始化时,世界坐标系和当前绘图坐标系是重合的。当用glTranslatef(),glScalef(), glRotatef()对当前绘图坐标系进行平移、伸缩、旋转变换之后, 世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相 对当前绘图坐标系来讲的

 


 

OpenGL中的6种坐标系

OpenGL中存在6种坐标系,

1. Object or model coordinates

2. World coordinates

3. Eye (or Camera) coordinates

4. Clip coordinates

5. Normalized device coordinates

6. Window (or screen) coordinates

从object coordainates到world coordinates再到camera coordinate的变换,在OPENGL中统一称为model-view转换,初始化的时候,object coordinates和world coordinates还有camera coordinates坐标重合在原点,变换矩阵都为Identity。model-view matix转换points,vectorsd到camera坐标系。

 

在opengl编程中,有个困惑的问题,就是那个坐标系是不动的,我想是你想参考坐标系是不动的。比如我想建立了一个object,放到 camera坐标系中,这时,我以camera的原点为参考点。当然,我想看这个物体的时候,我就以object的原点为参考点,移动camera坐标系的原点,就可以看到object了。好像写了一堆废话,呵呵。

 

 

其中四种坐标经常要在程序中用到:世界坐标,物体坐标,设备坐标和眼坐标

 

世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。

将物体放到场景中也就是将物体平移到特定位置、旋转一定角度,这些操作就是坐标变换。OpenGL中提供了glTranslate*/glRotate*/glScale*三条坐标变换命令,利用OpenGL的矩阵运算命令,则可以实现任意复杂的坐标变换。

 

非常重要:OpenGL 中有一个坐标变换矩阵栈(ModelView),栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。OpenGL中的坐标变换都是通过矩阵运算完成的,与图形学课本的描述完全一致。要注意的是变换中的矩阵乘法是左乘,而矩阵乘法与算术乘法不同,不符合交换律(万一不明白去看矩阵代数书好了)。

 

glTranslate*(x,y,z):平移,参数为各轴向的移动量。
glRotate(d,x,y,z):旋转,第一个参数为转动的度数,后三个参数表明是否绕该轴旋转。通常x,y,z中只有一个为1,其余为0,用连续几条旋转命令完成复杂旋转。由于矩阵运算的左乘特点,旋转命令的顺序与旋转动作的顺序正好相反

 

物体坐标是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。

 

眼坐标是以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。

 

同样的,有投影变换矩阵栈(Projection),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。前面提到过的视见体设定其实就是在建立该矩阵。

 

设备坐标:OpenGL 的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。在屏幕、打印机等设备上的坐标是二维坐标。值得一提的是,OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。

 

矩阵栈切换:glMatrixMode(GL_MODELVIEWING或GL_PROJECTION);本命令执行后参数所指矩阵栈就成为当前矩阵栈,以后的矩阵栈操纵命令将作用于它。

 

矩阵栈操纵命令:
glPushMatrix(); 当前矩阵入栈,这时矩阵栈将栈顶值压入栈。
glPopMatrix(); 栈顶出栈,通常与上一条命令配合使用。
glLoadIdentity(); 将栈顶设为不变矩阵(就是对角线全为1其它为0的那个)。
glMultMatrix(M);将栈顶T设为M·T。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值