变换Transformation是计算机图形学中的基础概念,用于描述和操作物体在二维或三维空间中的位置、方向和大小。

基本变换类型
缩放变换(Scale)
如图所示的坐标轴内物体缩放,其数学变换公式为:
x′y′=s⋅x=s⋅y
矩阵格式表述为:
[x′y′]=[s00s][xy]
而以此推广为非对称缩放变化:

此处的矩阵表述如下所示:
S=[sx00sy]=[0.5001.0]
[x′y′]=[sx00sy][xy]
镜像变换(Reflection)
如下图所示,对于镜像变换,也是直接修改x,y的值就好

其数学变换与矩阵表达如下所示:
{x′=−xy′=y
[x′y′]=[−1001][xy]
错切变换(Shear)

如上图所示:变换后的图形每个点的y坐标都没变,对于左上角的点来说变化应该是0+a,对于右上角的点来说变化应该是1+a,对于左边中间的点来说变化应该是0+a/2,所以每个点的变化应该是:
x′=x+ay
其矩阵表达为:
[x′y′]=[10a1][xy]
旋转变换(Rotation)

我们假设旋转角为
以原来的原点、x轴点、y轴点为例进行观察

原本的x轴点从(x,0)变为( x* cosθ, x* sinθ),而原本的y轴点由(0,y)变为(-y*sinθ,y * cosθ).
{x′=ax+byy′=cx+dy
这里我们假设原本的坐标向量(x,y)乘以一个旋转矩阵向量R从而得到了现在的坐标向量(x’,y’)
[x′y′]=[acbd][xy]
其公式推导如下:

得到的推导结果:
Rθ=[cosθsinθ−sinθcosθ]
x′=Mx其中M=[acbd]
⏰以上的变换统称线性变换,线性变换在矩阵中的定义是可以通过一次乘法直接得到结果的运算

平移变换(Translation)

而平移变换看似简单,却无法用线性变换矩阵来表示,其数学表达如下:
{x′=x+txy′=y+ty
其写为矩阵表达如下:
[x′y′]=[acbd][xy]+[txty]
人类总是犯懒的,最想做的事就是一步到位而不要这么多繁琐的操作,为了解决这个问题,引入齐次坐标的概念(所谓齐次坐标暂且可以先理解为加了一个坐标轴,用于将平移变换统一到我们的一般变换中),齐次后的矩阵表达式如下所示:
x′y′w′=100010txty1⋅xy1=x+txy+ty1
而之前的所有变换操作在齐次坐标下仍然可用:
Scale:
S(sx,sy)=sx000sy0001
Rotation:
R(α)=cosαsinα0−sinαcosα0001
Translation:
T(tx,ty)=100010txty1
注意⚠:当图像进行多个变换时,其复合表达式应该从右往左写,并且乘法交换率在矩阵中并不适用
M=T(tx,ty)⋅R(α)⋅S(sx,sy)
如上式,表示的是某图像先缩放,然后旋转,最后后再平移。
3D变换
3D变换相对于2D变换来说只是多增加了一个维度,可由2D变换举一反三得来:
Scale:
S(sx,sy,sz)=sx0000sy0000sz00001
Translation:
T(tx,ty,tz)=100001000010txtytz1
3D旋转
3D旋转与2D旋转也基本一直,观察如下矩阵表示可以感受其几何意义:绕X轴旋转则x相关坐标无变化,所以x除对角线外的元素均为0,其余两个轴同理.
Rx(α)=10000cosαsinα00−sinαcosα00001Ry(α)=cosα0−sinα00100sinα0cosα00001Rz(α)=cosαsinα00−sinαcosα0000100001
而绕y轴旋转有一点特殊,他在旋转之外进行了一个转置,这样做的原因是源于向量的叉乘:
X×YY×ZX×Z=Z=X=−Y
罗德里格斯旋转公式
图形学的最终目的是为了将三维中的物体渲染成二维里的图像,在现实生活中如何照一张照片?
-
找个好地方摆pose(Model变换)
-
把相机放个好角度(View变换)
-
按快门(投影Projection变换)
简称MVP🤭
视图View变换–如何摆放相机的角度
-
决定相机的位置
-
决定相机看向的方向
-
决定相机头朝上的方向
考虑到我们要实现下面一种情况:一个无限大的场景中,相机和要拍摄的物体随意移动,只要相机对于某物体的相对变换(位置、朝向、缩放)相同,那么在相机拍摄出的画面中,该物体永远相同(不考虑光照)。

为了简化计算,一般将相机的位置永远规定在(0,0,0),并且其朝向永远和-Z轴相同,视为一个计算机图形学中的约定。

如上图所示,要把摄像机归到原点分三步
- 平移摄像机至(0,0,0)对原本的坐标点做平移变换
Tview=100001000010−xe−ye−ze1
得到变换矩阵
Mview=Rview⋅Tview=xg^×t^xt^x−g^0yg^×t^yt^y−g^0zg^×t^zt^z−g^0−e⋅(g^×t^)−e⋅t^e⋅g^1
(其中 e=(xe,ye,ze) 是相机位置)
将Mview应用到相机,相机归零,同时也需要将Mview应用到其他所有物体,让物体和相机的相对位置保持不变
投影变换


投影变换分为两种,一种是正交投影,一种是透视投影。其最核心的区别在于:透视投影会造成一个“近大远小”的现象,用一个梗来解释就是“道理我都懂,但是鸽子为什么这么大”🙂

提示⏰:在现代游戏开发中,很多2D游戏是使用3D引擎去做的开发,然而其视图仍然能保持2D的感觉,使用的投影方式就正交投影。
正交投影

如上图所示,我们延续之前相机坐标归于原点的思想,可以得到下面的思维链条:
但在计算机图形学的实际过程中,有着更简化的计算方式,如下图所示

视口是个(l,r)(b,t)(f,n)的长方体,想让他变成[-1,1]³中只需要
- 先将立方体的中心平移到原点
- 在将立方体缩放到[-1,1]³中
Mortho=r−l20000t−b20000n−f200001⋅100001000010−2r+l−2t+b−2n+f1
透视投影
透视投影是使用最广泛的投影方法
传统的欧式几何是在同一平面内生效的法则,对于不同平面就会造成照片中近大远小的情况

对于一个使用透视投影的绘制,应该怎样进行呢,如下图所示:

老师的方法是,先将Frustum远平面及远平面到近平面之间的所有平面挤压到近平面大小,
变成Cuboid的样子,然后做一次正交投影。
怎样做挤压?
- 对于除近平面外的任意一个点,通过挤压后该点的高度y要变成和近平面一样的y’
- 从侧面看Frustum的话,如下图,可以形成两个相似三角形,即可得出y‘=(n/z)y
- 同理x’=(n/z)x

可以得到以下数学表达:
x′y′=znx=zny(similar to x′)
将其表示为齐次坐标的形式:
xyz1⇒nx/zny/zunknown1mult. znxnystill unknownz
现在我们对于投影的变换(挤压部分)有如下表达:
Mpersp→ortho(4×4)xyz1=nxnyunknownz
显而易见可以推理出M的部分值
Mpersp→ortho=n0?00n?000?100?0

想补全这个矩阵,需要用到两条已知的性质
- 近平面的点坐标(x,y,z)都不会发生变化
- 远平面的点z的值不会发生变化(因为我们采用的方法是先压缩后正交)
代入第一条性质(z值代为n)
xyn1⇒xyn1=nxnyn2n
显然发现第三行的计算结果n方与x,y均无关系,故设第三行为 (0,0,A,B),则其满足
(00AB)xyn1=n2
将其展开推导:
An+B=n2
显然该式有无穷多解,现在结合上面第二条性质的特殊点–即远平面上的中心点压缩后仍然是原来的位置,我们设其坐标为(0,0,f),带入数学表达式,并写为统一格式。
00f1⇒00f1=00f2f
展开得到:
Af+B=f2
联立两式解得:
{An+B=n2Af+B=f2⟶{A=n+fB=−nf
至此解得了完整的压缩变换矩阵:
Mpersp→ortho=n0000n0000n+f100−nf0
对压缩结果再进行一步正交投影即可得到最终结果
Mpersp=Mortho⋅Mpersp→ortho