最近在学习OpenGL,但是书中的各种坐标系搞得我颇为痛苦,既不知道各种坐标系是做什么用的,也不知道各自是如何转换的,往往是看书看到吐。一番纠结之后,还是得自己去找资料解决,下面就把我个人学到的各种坐标系的知识分享出来,省的后来人跟我一样痛苦了。
首先声明一点,对于三维物体,openGL使用右手坐标,从左到右,x递增,从下到上,y递增,从远到近,z递增。
但是对于二维问题,在OpenGL中x轴与y轴的正方向分别是向右和向上,也就是说可以把屏幕左下角设为原点,这样屏幕中的点坐标都为正值。但是对于GLUT实用工具集来说,由于它经常与窗口进行交互,x轴与y轴的正方向分别是向右和向下,也就是说想使屏幕中点的坐标都为正值,我们需要把屏幕的左上角设为原点。所以编程时经常需要考虑两种坐标系,挺麻烦的。
OpenGL坐标系可分为:世界坐标系和当前绘图坐标系:
- 世界坐标系以屏幕中心为原点(0, 0, 0)。你面对屏幕,你的右边是x正轴,上面是y正轴,屏幕指向你的为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1)。注意:世界坐标系是始终固定不变的。
- 当前绘图坐标系是 绘制物体时的坐标系。程序刚初始化时,世界坐标系和当前绘图坐标系是重合的。当用
glTranslatef()
,glScalef()
,glRotatef()
对当前绘图坐标系进行平移、伸缩、旋转变换之后,世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()
等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相对当前绘图坐标系来讲的。
总的来说OpenGL中存在6种坐标系:
- Object or model coordinates
- World coordinates
- Eye (or Camera) coordinates
- Clip coordinates
- Normalized device coordinates
- Window (or screen) coordinates
从object coordainates到world coordinates再到camera coordinate的变换,在OPENGL中统一称为model-view转换,初始化的时候,object coordinates和world coordinates还有camera coordinates坐标重合在原点。
其中四种坐标经常要在程序中用到:世界坐标,物体坐标,设备坐标和眼坐标。
- 世界坐标系(World coordinates)是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。
- 物体坐标(Object or model coordinates)是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。
- 眼坐标系或照相机坐标系( Eye (or Camera) coordinates)是以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。
- 设备坐标(Normalized device coordinates)OpenGL 的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。在屏幕、打印机等设备上的坐标是二维坐标。值得一提的是,OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。
附:OpenGL 中有一个坐标变换矩阵栈(ModelView)
,栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。同样的,有投影变换矩阵栈(Projection)
,栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。前面提到过的视见体设定其实就是在建立该矩阵。
矩阵栈操纵命令 | 描述 |
---|---|
glPushMatrix(); | 当前矩阵入栈,这时矩阵栈将栈顶值压入栈。 |
glPopMatrix(); | 栈顶出栈,通常与上一条命令配合使用。 |
glLoadIdentity(); | 将栈顶设为不变矩阵(就是对角线全为1其它为0的那个)。 |
glMultMatrix(M); | 用矩阵M右乘当前矩阵,注意是右乘。在OpenGL中定义的变换都是通过右乘(postmultiplication)作用于当前矩阵的。 |