openGL中使用的是右手坐标系
- 右手坐标系:伸开右手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向
-
左手坐标系:伸开左手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向
两者的区别主要是两者Z轴的方向是相反的
一、坐标系
openGL中主要的几种坐标系
-
世界坐标系
以屏幕中心为原点(0,0,0),当你面对屏幕时,右边是X正轴,上方是Y轴正轴,屏幕指向你的方向为Z轴正轴。窗口范围是从(-1,1),即屏幕左下角坐标为(-1,-1,0),右上角坐标为(1,1,0)。我们用这个坐标系描述物体及光源的位置
将物体放到场景中(平移、旋转等),这些操作就是坐标变换。openGL中提供了glTranslate / glScale / glRotate 三条坐标变换命令,利用变换矩阵运算命令,则可以实现任意复杂的坐标变换 -
惯性坐标系
由世界坐标系和物体坐标系联合理解
是物体坐标系的旋转,只是一个中间状态的描述,方便物体坐标系切换到世界坐标系 -
物体坐标系/局部空间坐标系
是以物体某一点为原点建立的坐标,该坐标仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,可以视为一个整体 -
摄像机坐标系:观察者坐标系
以观察者为原点,视线的方向为Z轴的正方向。openGL管道会将世界坐标先变换到观察者坐标,然后进行裁剪。只有视线范围内的场景才会进行下一步的计算
坐标变换过程
openGL在每次顶点着色后,可见顶点都是标准化设备坐标,即每个顶点的x、y、z值都应该在-1到1之间,超出这个范围的顶点是不可见的
将坐标转换为标准化设备坐标,接着再转换为屏幕坐标的过程是分步进行的,这个过程中,物体的顶点在最终转换为屏幕坐标之前还会被转换到多个坐标系统。在这些过度的特定坐标系中,一些操作或运算更加方便。
变换矩阵
为了将坐标从一个坐标系变换到另一个,我们需要用到几个变换矩阵,常用有模型(Model)、观察(View)、投影(Projection)三个矩阵
坐标变换矩阵栈
栈顶是当前坐标变换矩阵,进入openGL管道的每个坐标都会先乘以这个矩阵,结果才是对应点在具体场景中的世界坐标。openGL中的坐标变换是通过矩阵运算完成的。变换中的矩阵乘法是叉乘,结果中包含方向,不符合交换律。
物体顶点的起始坐标是局部坐标,之后会转换为世界坐标、观察者坐标、裁剪坐标,最后以屏幕坐标的形式结束。可以参考下面这张图
二、坐标空间
局部空间
指的是物体所在的坐标空间,即对象最开始所在的地方,相对于这个物体来说是局部的
世界空间
是指物体的顶点相对于世界的坐标空间,物体分散在世界上摆放,则物体的坐标会从局部空间变换到世界空间。该变换是由模型矩阵(Model Matrix)实现的
- 模型矩阵 Model Matrix
是一种变换矩阵,可以通过对物体进行位移、缩放、旋转来将它置于它该在的位置和朝向。可以想象为你想一把椅子放在一个房间内,需要先将它缩小(它在局部空间中太大了),并将它移动到房间的某个位置,然后在y轴上往左右旋转一点以摆放整齐。就是将局部坐标变换到场景/世界中的不同位置
观测空间/观察空间
观察空间也被称为openGL的摄像机Camera,所以有时候也称为摄像机空间(Camera space) 或视觉空间(Eye space)。观察空间是将世界空间坐标转换为用户视野前方的坐标而产生的结果。也就是说,观察空间,就是从摄像机的视角所观察到的空间。
而这通常是由一系列的位移和旋转的组合来完成的,平移/旋转场景从而使特定的对象被变换到了摄像机的前方。
这些组合在一起的变换通常存储在一个 观察矩阵(View Matrix) 里,它被用来将世界坐标变换到观察空间。
裁剪空间
- 裁剪过程
一个顶点着色器运行的最后,openGL希望所有的坐标都能落在一个特定的范围内(-1,1),任何在这个范围外的点都应该被裁剪(Clipped)掉。被Clipped的就会被忽略,余下的坐标就将变为屏幕上可见的片段。这个空间称为裁剪空间
为了将顶点坐标从观察者坐标变换到裁剪空间,我们需要定义一个投影矩阵(Projection Matrix),它可以指定一个范围的坐标,投影矩阵会将在这个指定范围内的坐标变换为标准化设备坐标的范围(-1,1),所有在范围外的坐标不会被映射在-1到1的范围之间,所以会被裁剪掉
比如在每个维度上的-1000到1000,裁剪之后,坐标(12400,500,700)将是不可见的,因为其x坐标超出了范围(大于1000),它被转换为一个大于1的标准化设备坐标,所以被裁剪掉了
投影:将特定范围内的坐标转换为标准化设备坐标系的过程,称为投影
平截头体Frustum:由投影矩阵创建的观察箱被称为平接头体,每个出现在平截头体范围内的坐标都会最终出现在用户的屏幕上。(不太理解,是不是类似一个圆锥或圆柱,从中间用刀切开,那个切面的范围,就相当于平截头体???) - 透视除法 Perspective Division
一旦所有顶点被变换到裁剪空间,透视除法将会执行。这个过程中我们将位置向量的x,y,z分量分别除以向量的齐次分量w(深度)
透视除法是将4D裁剪空间坐标变换为3D标准化设备坐标的过程。这一步会在每一个顶点着色器运行的最后被自动执行。
之后,最终的坐标会被映射到屏幕空间中(使用glViewport中的设定),并被变换成片段
将观察坐标变换为裁剪坐标的投影矩阵可以分为两种不同的形式:正投影矩阵(Orthographic Projection Matrix)或透视投影矩阵(Perspective Projection Matrix)
透视投影
现实生活中,离观察者越远的东西看起来越小,这个现象称之为透视(Perspective)
openGL中的透视效果是由透视矩阵实现的。这个透视矩阵将给定的平截头体范围映射到裁剪空间,除此之外还修改了每个顶点坐标的w(深度)值,从而使得离观察者越远的顶点坐标的w分量越大。被变换到裁剪空间的坐标都会在-w到w之间。所以,一旦坐标在裁剪空间内之后,透视除法就会被应用到裁剪空间坐标上
正投影
当使用正投影时,每一个顶点坐标都会直接映射到裁剪空间中而不经过任何精细的透视除法(它仍然会进行透视除法,只不过w分量没有被改变,保持为1,所以不起作用)
三、将坐标系统组合在一起
我们为上述的每一个步骤都创建了一个变化矩阵:模型矩阵、观察矩阵、投影矩阵,一个顶点坐标将会根据以下过程被变换到裁剪坐标
Vclip = Mpro * Mview * Mmodel * Vlocal
这一系列的矩阵变换需要从右向左,依次是M V P。最后的顶点应该被赋值到顶点着色器中的gl_Position,openGL会自动进行透视除法和裁剪
视口变换:openGL对裁剪坐标执行透视除法从而将它们变换到标准化设备坐标,然后openGL会使用glViewPort内部的参数来将标准化设备坐标映射到屏幕坐标,每个坐标都关联了屏幕上的一个点,这个过程称为视口变换
上述过程,裁剪之前的坐标变换可以由开发者参与,裁剪和裁剪后续的动作,是系统完成的
参考:
https://blog.csdn.net/meegomeego/article/details/8686816
https://www.cnblogs.com/tandier/p/8110977.html