变换,指将数据通过一定的规则进行转换,通常可以用矩阵来进行表示。
简介
- 在计算机图形学中,变换的使用非常常见,如:平移、缩放、旋转等。变换主要分为
- 线性变换
- 可以保留矢量加和标量乘的变换,即
- f(x) + f(y) = f(x + y)
- kf(x) = f(kx)
- 缩放(scale)、旋转(rotation)、错切(shear)、镜像(mirroring)、正交投影(orthography projection)等
- 可以保留矢量加和标量乘的变换,即
- 仿射变换
- 线性变换和平移变换的合并
- 线性变换
- 对于常见的变换,其变换矩阵分别为
- 平移
- 缩放
- 旋转(绕x、y、z轴)
- 对于复合变换,需要按照先缩放,再旋转,最后平移的顺序,才能保证最后得到正确的效果。
- 在 Unity 中,坐标系是按照 y-x-z 的逐级组合的,如果绕世界坐标系下的固定坐标轴旋转,需要按照 zxy 的顺序。如果绕自身坐标系旋转,由于旋转时自身坐标系也会发生改变,根据坐标系的次序,需要按照 yxz 的顺序进行旋转,即
- 在图形学计算中,从CPU传入的顶点坐标,需要从模型空间,变换到世界空间,再变换到视图空间,再变换到裁剪空间,最后变换到屏幕空间。从模型空间变换到裁剪空间,就是常说的 MVP 变换。
模型变换
- 模型变换,即将坐标从模型空间变换到世界空间。在 Unity 中,如果一个 GameObject 没有父节点,那么其坐标即为世界空间下的坐标。如果存在父节点,则其自身坐标即为模型空间下的坐标,需要进行变换。变换为复合变换,将所有父节点的信息累计起来,进行平移、缩放和旋转。假设父节点的坐标为(x,y,z),角度为(θ,0, 0),则最终模型变换的变换矩阵即为
视图变换
- 相机决定了渲染使用的视角,在视图空间下,相机的坐标为原点坐标,x轴正向为右方,y轴正向为上方,z轴正向为相机后方。尽管 Unity 在模型空间和世界空间下使用的都是左手坐标系,但在观察空间下, Unity 和 OpenGL 一样,使用右手坐标系,因此,相机的正前方为 -z 。
- 为了将物体变换到视图空间下,需要对应的变换矩阵。若将相机变换到世界坐标下的原点,并旋转到与坐标轴重合,再将相机的 z 方向取反,此时对应物体经过同样的变换后,在世界空间下的信息即为在视图空间下的信息。假设相机在世界空间下的坐标为(x,y,z),角度为(θ,0, 0),则视图变换矩阵为
投影变换
- 相机最终渲染的范围为其视锥体范围,在视锥体内的正常渲染,视锥体外的则剔除,与视锥体相交的则会被裁剪,只保留视锥体内的部分。对于正交投影,视锥体是一个长方体,计算对象是否在其范围相对比较简单,而透视投影是一个锥体,计算难度则相对较大。另外,由于每个相机都有各自的参数,所以各自的视锥体都不一样,因此计算起来也更加复杂。为了能统一到一个通用、简单的结构下进行计算,则需要进行投影变换。
- 视锥体的一些表示
- l :近裁剪平面的左边
- r :近裁剪平面的右边
- t :近裁剪平面的上边
- b :近裁剪平面的下边
- n :近裁剪平面的距离(正)
- f :远裁剪平面的距离(正)
正交投影
- 正交模式下,视锥体是一个长方体,要将长方体视锥体变换到以 (0, 0) 为中心, [-1, 1] 范围的正方体内,因此需要执行两个步骤
- 将视锥体中心移动到坐标原点
- 将视锥体进行缩放,形成 [-1, 1] 的正方体
- 所以正交投影矩阵为
透视投影
- 透视模式下,视锥体是一个截掉顶部的锥体,和正交模式不一样,所以需要进行的操作为
- 将视锥体变换为长方体
- 按照正交投影进行投影变换
- 为了将视锥体变换为长方体,首先需要将视锥体的 x、y 坐标投影到近裁剪平面对应的坐标值。
- 可以看到,视锥体上的点的关系为
- 因此,变换过程为
- 可以推出变换矩阵
- 由于远近裁剪平面经过变换后,还是保持不变,对于近裁剪平面上的点,z = z' = -n ,则有
- 因此可以得到,变换矩阵为
- 同样,对于远裁剪平面上的点,z = z' = -f ,则有
- 可以得到
- 因此变换矩阵为
- 则最终透视投影的变换矩阵为
齐次除法(透视除法)
- 经过投影变换后,得到的视锥体,需要投影到屏幕空间中。然而可以发现,正交投影和透视投影得到的视锥体并不是统一的,所以需要统一转换到 NDC(Normalized Device Coordinates)中,即将 x、y、z、w 都除以 w 分量。
- 正交投影变换为 由于 w 分量为 1,因此齐次除法后保持不变。
- 透视投影变换为 由于 w 分量为 -z,所以 x、y、z 都要除以 -z,从而将视锥体转换到 [-1, 1] 范围里。
总结
- 计算机图形学中,变换的应用非常多,渲染时基本上离不开坐标变换,理解各个过程的变换矩阵,也有助于理解整个渲染的过程。