OpenGL最终将图形渲染到的设备屏幕本质上是2D的,我们对图形进行渲染的过程就是将3D场景转换为最终的2D场景的过程。
OpenGl中定义的点从用户构造模型的局部坐标系,经过模型变换转为世界坐标系,再经过视变换转换为相机坐标系,再经过投影变换转换为裁剪坐标系,再进行透视除法转换为规范化设备坐标系(NDC),最后经过视口变换映射到屏幕坐标系。 坐标变换流程如下图所示: 注意: OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系。其中的坐标变换过程如透视除法、视口变换是有OpenGL自动执行的。 而局部坐标系(模型坐标系)、世界坐标系和照相机坐标系都是为了方便用户设计而自定义的坐标系。其中的坐标变换过程如模型变换、视变换、投影变换可以根据用户需要自行指定。 上述所有变换过程都是在顶点着色器中执行的。(对于OpenGL绘制管线,以前是基于固定功能的绘制管线,在OpenGL 3.1版本之后移除了固定功能的管线绘制,取而代之使用着色器来进行绘制) 从矩阵坐标角度来看,流程如下: 1.局部坐标系/对象坐标系->世界坐标系 也就是通过模型变换,将物体局部坐标转换到世界坐标系坐标。模型变换包括平移、旋转、缩放等。 在固定功能绘制管线情况下,默认OpenGL中model-view与projection矩阵都是单位矩阵。如果没有应用任何变换,对象坐标系、世界坐标系、照相机坐标系和裁剪坐标系是重合的。
2.世界坐标系->照相机坐标系 实际上,照相机的指向位置、观察者方向都是在世界坐标系下指定的。 那么,为什么要将世界坐标系转换为照相机坐标系呢? 因为最终的成像都要通过照相机模型来定义的,转换到照相机坐标系能够简化数学计算。该转换也可以理解为从照相机看到的世界坐标系中场景的样子。 现实世界中,我们通过移动照相机来观察物体的不同角度;而在OpenGL中,照相机位置是固定于(0,0,0)并朝向-Z轴的,那么我们通过移动场景来完成这个转换。参考:https://gamedev.stackexchange.com/questions/40741/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内部的参数来将标准化设备坐标系映射到屏幕坐标,每个坐标都关联了屏幕上的一个点,这个过程称为视口变换。
参考: http://www.360doc.com/content/14/1028/09/19175681_420513219.shtml http://www.codinglabs.net/article_world_view_projection_matrix.aspx
