OpenGL坐标系系统
- Object or model coordinates 物体或者模型坐标系
- World coordinates 世界坐标系
- Eye (or Camera) coordinates 观察者或者相机坐标系
- Clip coordinates 裁剪坐标系
- Normalized device coordinates 规范化设备坐标系
- Window (or screen) coordinates 窗口或者屏幕坐标系
坐标系转换过程就是OpenGL最终将图形渲染到的设备屏幕的流程,屏幕本质是2D空间,对图形进行渲染的过程就是将3D场景转换为最终的2D场景的过程。
图形进行渲染流程
OpenGl中定义的点从用户构造模型的局部坐标系,经过模型变换转为世界坐标系,再经过视变换转换为相机坐标系,再经过投影变换转换为裁剪坐标系,再进行透视除法转换为规范化设备坐标系(NDC),最后经过视口变换映射到屏幕坐标系。
坐标系意义概括
物体/模型坐标系
世界坐标系
它是一个特殊的坐标系,它建立了描述其他坐标系所需要的参考系。也就是说,可以用世界坐标系去描述其他所有坐标系或者物体的位置。所以有很多人定义世界坐标系是“我们所关心的最大坐标系”,通过这个坐标系可以去描述和刻画所有想刻画的实体。世界坐标系又称全局坐标系
或者宇宙坐标系
。
世界坐标系以屏幕中心为原点(0, 0, 0),右手螺旋坐标系,x轴从左到右,y轴从下到上,大拇指所指方向/垂直屏幕向外为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1),即屏幕左下角坐标为(-1,-1),右上角坐标为(1,1)。我们用这个坐标系来描述物体及光源的位置,或是将物体放到场景中也就是将物体平移到特定位置、旋转一定角度,这些操作就是坐标变换。OpenGL中有一个坐标变换矩阵栈(ModelView),栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。OpenGL中的坐标变换都是通过矩阵运算完成的,与图形学课本的描述完全一致。要注意的是变换中的矩阵乘法是左乘,而矩阵乘法与算术乘法不同,不符合交换律。
观察者/相机坐标系
以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。同样的,有投影变换矩阵栈(Projection),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。前面提到过的视见体设定其实就是在建立该矩阵。
裁剪坐标系
将投影范围通过插值转化为CVV(Clip Coordinate System)以便于裁剪。
设备坐标系
OpenGL 的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。
屏幕坐标系
从设备坐标系(NDC),最后经过视口变换映射到屏幕坐标系.需要视口变换是因为OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。
- 屏幕坐标系: 原点在左上角,X轴向右,Y轴向下。
- GL坐标系: 原点在左下角,X轴向右,Y轴向上.
视口变换:使用 glViewPort 内部的参数来将标准化设备坐标映射到屏幕坐标,每个坐标关联一个屏幕上的点的过程
图示坐标系转换流程
Tips
OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系。其中的坐标变换过程如透视除法、视口变换是有OpenGL自动执行的。而局部坐标系(模型坐标系)、世界坐标系和照相机坐标系都是为了方便用户设计而自定义的坐标系。其中的坐标变换过程如模型变换、视变换、投影变换可以根据用户需要自行指定。上述所有变换过程都是在顶点着色器中执行的。(对于OpenGL绘制管线,以前是基于固定功能的绘制管线,在OpenGL 3.1版本之后移除了固定功能的管线绘制,取而代之使用着色器来进行绘制)
矩阵坐标角度流程
1.局部坐标系/模型坐标系 ->世界坐标系
通过模型变换,将物体局部坐标转换到世界坐标系坐标。模型变换包括平移、旋转、缩放等。在固定功能绘制管线情况下,默认OpenGL中model-view与projection矩阵都是单位矩阵。如果没有应用任何变换,对象坐标系、世界坐标系、照相机坐标系和裁剪坐标系是重合的。
2. 世界坐标系->照相机坐标系
实际上,照相机的指向位置、观察者方向都是在世界坐标系下指定的。
那么,为什么要将世界坐标系转换为照相机坐标系呢?
因为最终的成像都要通过照相机模型来定义的,转换到照相机坐标系能够简化数学计算。该转换也可以理解为从照相机看到的世界坐标系中场景的样子。现实世界中,我们通过移动照相机来观察物体的不同角度;而在OpenGL中,照相机位置是固定于(0,0,0)并朝向-Z轴的,那么我们通过移动场景来完成这个转换。参考:why-do-we-move-the-world-instead-of-the-camera. 总结来说:对于一个中心点位于原点的物体,照相机也位于原点。为了对物体某+Z面成像,可以通过两种方式实现:
- 物体不动,照相机动。即将照相机从原点沿着+Z轴方向移动某个单位距离
- 照相机不动,物体动。即将物体从原点沿着-Z轴方向移动某个单位距离。
两种方法实现的效果相同的。从世界坐标系到照相机坐标系,有多重指定照相机的方式,其中包括常用的gluLookAt函数构造的UVN相机坐标系。
3.照相机坐标系->裁剪坐标系
该过程是通过投影完成的。投影就是将物体投影到平面的过场。因为OpenGL采用虚拟相机成像模型,因此也使用了正投影和透视投影两种方式。
正投影:又叫平行投影,特点就是无论物体距离摄像机多远,投影后的物体大小尺寸不变。该投影的视景体是一个矩形的平行管道,及长方体。常用语建筑图绘制、计算机辅助设计等行业,这些行业要求投影后的物体尺寸与角度不变,以方便施工制造。
透视投影:特点是离视点近的物体大,离视点远的物体小,远到极限变消失,称为灭点。透视投影更接近于真实世界的投影方式。该投影视景体类似一个顶部与底部都被切除掉的棱锥。常用语动画、视觉仿真等行业。
OpenGL使用函数
glOrtho(xleft, xright, ybottom, ytop, znear, zfar)
正投影函数
void glFrustum(GLDouble left, GLDouble right, GLDouble bottom, GLDouble top, GLDouble nearVal, GLDouble farVal);
透视投影函数或者下面透视投影函数
glPerspective(GLDouble fovy, GLDouble aspect, GLDouble zNear, GLDouble zFar);
4.裁剪坐标系->规范化设备坐标系
执行透视除法即可实现裁剪坐标系到规范化设备坐标系的转换。
5.规范化设备坐标系->屏幕坐标系
从规范化设备坐标系到屏幕坐标系的转换基本上是一个线性映射关系。使用glViewPort内部的参数来将标准化设备坐标系映射到屏幕坐标,每个坐标都关联了屏幕上的一个点,这个过程称为视口变换。
常见坐标转换和坐标系栈操作
坐标变换命令:
- glTranslate*(x,y,z):平移,参数为各轴向的移动量
- glRotate(d,x,y,z):旋转,第一个参数为转动的度数,后三个参数表明是否绕该轴旋转。通常x,y,z中只有一个为1,其余为0,用连续几条旋转命令完成复杂旋转。由于矩阵运算的左乘特点,旋转命令的顺序与旋转动作的顺序正好相反。
- glScale: 缩放
矩阵栈切换
glMatrixMode(GL_MODELVIEWING或者GL_PROJECTION)
本命令执行后参数所指矩阵栈就成为当前矩阵栈,以后的矩阵栈操纵命令将作用于它。
矩阵栈操纵
glPushMatrix(): 当前矩阵入栈,这时矩阵栈将栈顶值压入栈
glPopMatrix(): 栈顶出栈,通常与上一条命令配合使用
glLoadIdentity(): 将栈顶设为不变矩阵(就是对角线全为1其它为0的那个)
glMultMatrix(M): 将栈顶T设为M·T
博客参考:https://blog.csdn.net/meegomeego/article/details/8686816 && https://blog.csdn.net/JeffersonZHabc/article/details/90488276