三、OpenGL下的坐标系
OpenGL下的坐标系有六种:
- World Coordinates(世界坐标系)
- Object Coordinates(对象坐标系、模型坐标系、局部坐标系或当前绘图坐标系)
- Eye Coordinates(眼坐标系或照相机坐标系)
- Clip Coordinates(裁剪坐标系)
- Normalized Device Coordinates (NDC) (归一化设备坐标系)
- Window Coordinates (Screen Coordinates)(屏幕坐标)
为什么需要这么多的坐标系统?
OpenGL希望在每次顶点着色器运行后,我们可见的所有顶点都为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说,每个顶点的x,y,z坐标都应该在-1.0到1.0之间,超出这个坐标范围的顶点都将不可见。我们通常会自己设定一个坐标的范围,之后再在顶点着色器中将这些坐标变换为标准化设备坐标。然后将这些标准化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标或像素。
将坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的,也就是类似于流水线那样子。在流水线中,物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统(Coordinate System)。将物体的坐标变换到几个过渡坐标系(Intermediate Coordinate System)的优点在于 :在这些特定的坐标系统中,一些操作或运算更加方便和容易,这一点很快就会变得很明显(摘自LearnOpenGL)
我们先来了解一下笛卡尔坐标系(直角坐标系)
2D笛卡尔坐标系
2D笛卡尔坐标系3D笛卡尔坐标系
3D笛卡尔坐标系视口
就是窗口中的一块矩形区域,小于等于窗口的大小,通过glViewport()函数设置。如下图:
视口
投影方式
2种:正投影(平行投影),类比如照镜子,不管远近,都是1:1绘制,一样大。一般显示2D效果
透视投影,远小近大,显示3D效果
平行投影和透视投影
世界坐标系 (World Coordinates)
世界坐标系始终是固定不变的。是OpenGL中用来描述场景的坐标系,属右手笛卡尔坐标系。
左手坐标系和右手坐标系
在世界、物体、照相机空间用的是右手坐标系
在规范化设备坐标系用的是左手坐标系
物体坐标系(Object Coordinates)
每个物体都有自己特定的坐标系,不同的物体之间的坐标系相互独立。
物体坐标系
惯性坐标系
惯性坐标系是为了简化世界坐标系到惯性坐标系的转化而产生的。惯性坐标系的原点与物体坐标系的原点重合,惯性坐标系的轴平行于世界坐标系的轴。引入了惯性坐标系之后,物体坐标系转换到惯性坐标系只需旋转,从惯性坐标系转换到世界坐标系只需平移。
坐标系之间的联系为什么要引入惯性坐标系?
因为物体坐标系转换到惯性坐标系只需要旋转,从惯性坐标系转换到世界坐标系只需要平移.
坐标系之间的联系
在机器人的物体坐标系中,y轴从脚指向头而x轴指向它的左边。绕物体坐标系的原点进行旋转。知道物体坐标系的轴与世界坐标系平行就得到了惯性坐标系。最后,把惯性坐标系的原点平移到世界坐标系的原点就完成了惯性坐标系到世界坐标系的转换。
眼坐标系(Eye Coordinates)
为啥要转换到眼坐标系呢?
可以这样理解,通过前面的MODEVIEW变换,这个世界坐标系中的场景已经绘制好了。这时候我们还不能看到场景哦,因为我们的观察位置还没定呢,而且如果我们眼睛(照相机)的位置不同,那么观察物体的角度则不同,那看到的场景的样子肯定也不同,所以要有这一步,把场景与我们的观察位置对应起来。
眼坐标系
裁剪坐标系(Clip Coordinates)
眼坐标到裁剪坐标是通过投影完成的。眼坐标通过乘以GL_PROJECTION矩阵变成了裁剪坐标。
image这个GL_PROJECTION矩阵定义了视景体( viewing volume),即确定哪些物体位于视野之内,位于视景体外的对象会被剪裁掉。除了视景体,投影变换还定义了顶点是如何投影到屏幕上的,是透视投影(perspective projection)还是正交投影(orthographic projection)。
归一化坐标系(Normalized Device Coordinates)
既然要规范化,那么就得先有一个规范。前面在投影部分也已经看到,每种投影,都有一个剪裁空间,称之为观察体,对正交投影来说是一个立方体,对透视投影来说是一个棱台。如果一个观察体是一个x、y、z坐标范围都是 [-1, 1] 的立方体,则称之为规范化立方体,这个就是所谓的规范。那么,将原来的观察体,映射到规范化立方体的过程,就是规范化。
一个格外需要注意的地方是,由于后面的屏幕坐标系通常是左手坐标系,所以这里的规范化观察体也使用左手坐标系,意味着 x 轴和 y 轴没有改变,但是 z 轴的正方向转了个。这带来的结果是,在这样的坐标系下,z 的坐标值越小,距离观察者(也就是你)越近。实际上,在opengl中,进行规范化之后,近裁剪平面的z轴坐标是 -1,远裁剪平面的z轴坐标是1。
归一化坐标系由裁剪坐标系下通过除以W分量得到。这个操作称为透视除法。NDC坐标很像屏幕坐标,但是还没有经过平移和缩放到屏幕像素。现在3个轴上的值范围均为[-1,1]。
透视除法屏幕坐标系(Window Coordinates)
通常将屏幕上的设备坐标称为屏幕坐标。设备坐标又称为物理坐标,是指输出设备上的坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的 X 轴向右为正,Y 轴向下为正,坐标原点位于窗口的左上角。
从NDC坐标到屏幕坐标基本上是一个线性映射关系。通过对NDC坐标进行视口变换得到。这时候就要用到函数glViewport(),该函数用来定义渲染区域的矩形,也就是最终图像映射到的区域。
屏幕坐标系
坐标变换的全局图
OpenGL最终的渲染设备是2D的,我们需要将3D表示的场景转换为最终的2D形式,前面使用模型变换和视变换将物体坐标转换到照相机坐标系后,需要进行投影变换,将坐标从相机—》裁剪坐标系,经过透视除法后,变换到规范化设备坐标系(NDC),最后进行视口变换后,3D坐标才变换到屏幕上的2D坐标,这个过程如下图所示
OpenGL顶点变换过程在上面的图中,注意,OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系,而局部坐标系(模型坐标系)、世界坐标系和照相机坐标系都是为了方便用户设计而自定义的坐标系,它们的关系如下图所示
关系图-
图中左边的过程包括模型变换、视变换,投影变换,这些变换可以由用户根据需要自行指定,这些内容在顶点着色器中完成;
-
图中右边的两个步骤,包括透视除法、视口变换,这两个步骤是OpenGL自动执行的,在顶点着色器处理后的阶段完成。
将坐标系统组合在一起
组合OpenGL 然后对裁剪坐标执行透视除法从而将它们变换到标准化设备坐标。OpenGL 会使用 glViewPort
内部的参数来将标准化设备坐标映射到屏幕坐标,每个坐标都关联了一个屏幕上的点。这个过程称为视口变换