本文已参与[新人创作礼]活动,一起开启掘金创作之路
图形学的数学基础(八):矩阵线性变换
我们可以通过添加一些值到它的坐标来平移一个点。 我们还可以利用三角函数来旋转矢量。 简而言之,矩阵只是将所有这些变换(缩放、旋转、反射、错切、平移)组合成一个单一结构的一种方式。 通过矩阵的方式我们可以方便的对空间中的点或矢量进行变换,而不用写一大堆的公式。这就是矩阵为何在图形渲染管线中存在重要意义的原因。图形中的任意变换都可以通过一个矩阵完成。 对同一个对象的多次变换可以通过矩阵乘积转换为单个矩阵。如下图:
注:本文所有推导和公式均使用列矢量形式。

线性变换
缩放(Scale)
沿主轴缩放
最简单的缩放是沿每个轴线应用单独的或者统一的缩放。
均匀缩放
保留原始对象的角度和比例, 使被缩放对象统一增大或者减少s因子。

[x丶y丶]=[S00S][xy]
同理三维空间中采用以下形式:
⎣⎡x丶y丶z丶⎦⎤=⎣⎡S000S000S⎦⎤⎣⎡xyz⎦⎤
非均匀缩放
如果希望"拉伸"或者"挤压"对象,则可以在不同方向上应用不同的缩放因子,这样会导致非均匀缩放。非均匀缩放不会保留原始对象的角度。

[x丶y丶]=[Sx00Sy][xy]
同理三维空间中采用以下形式:
⎣⎡x丶y丶z丶⎦⎤=⎣⎡Sx000Sy000Sz⎦⎤⎣⎡xyz⎦⎤
任意方向缩放
除了沿主轴线缩放外,还可以应用独立于坐标系的缩放,即沿任意方向的缩放。设n^缩放方向(缩放沿着n^执行),缩放因子s。以下将逐步实现沿任意方向缩放的方法。
step1: 推导表达式,给定任意矢量v,用v,s,n^计算v丶。基本思路是将矢量v在n^上投影,分解为v∥和v⊥。其中v∥根据k因子缩放,v⊥保持不变。以下为推导过程:

v=v∥+v⊥
v∥=(v.n^)n^
v⊥丶=v⊥=v−v∥=v−(v.n^)n^
v∥丶=sv∥=s(v.n^)n^
v丶=v⊥丶+v∥丶=v−(v.n^)n^+s(v.n^)n^=v+(s−1)(v.n^)n^
step2: 既然我们知道了如何缩放任意矢量,则可以计算出缩放后的基矢量值,将原始基矢量x=[10],y=[01]带入上式可得:
x丶=x+(s−1)(x.n^)n^=[10]+(s−1)([10].[nxny]).[nxny]=[10]+(s−1)nx.[nxny]=[1+(s−1)nx2(s−1)nxny]
y丶=[(s−1)nxny1+(s−1)(ny)2]
推导出二维和三维矢量空间沿任意方向n^缩放s的矩阵为:
Scale2(n^,s)=[1+(s−1)(nx)2(s−1)nxny(s−1)nxny1+(s−1)ny2]
Scale3(n^,s)=⎣⎡1+(s−1)(nx)2(s−1)nxny(s−1)nxnz(s−1)nxny1+(s−1)ny2(s−1)nynz(s−1)nxnz(s−1)nynz1+(s−1)nz2⎦⎤
反射(Reflection)
反射其实是一种特殊的缩放,即按照某个轴线执行-1缩放。
沿主轴线的反射
[x丶y丶]=[−1001][xy]
沿任意轴反射
根据沿任意轴缩放得到的矩阵公式,将-1带入,可得沿任意轴反射的矩阵公式:
Reflection2(n^)=[1+(−1−1)(nx)2(−1−1)nxny(−1−1)nxny1+(−1−1)ny2]
Reflection3(n^)=⎣⎡1+(−1−1)(nx)2(−1−1)nxny(−1−1)nxnz(−1−1)nxny1+(−1−1)ny2(−1−1)nynz(−1−1)nxnz(−1−1)nynz1+(−1−1)nz2⎦⎤
错切(Shaearing)
错切是一种“倾斜”坐标空间的变形。它将不均匀的拉伸空间,不保留角度。但是保留面积和体积。基本思路是将一个坐标的倍数添加到另一个坐标上。

[x丶y丶]=[10a1][xy]
二维错切矩阵公式:
Hx(s)=[10s1] (沿x轴方向拉拽)
Hy(s)=[1s01] (沿y轴方向拉拽)
三维错切矩阵公式:
Hxy(s,t)=⎣⎡10s01t001⎦⎤
Hxz(s,t)=⎣⎡1ss01t0t1⎦⎤
Hyz(s,t)=⎣⎡10ss1tt01⎦⎤
旋转(Rotation)
二维空间绕原点的旋转
在二维空间中只能绕点旋转,本小节公式和实例将旋转点限定为坐标系原点(绕任意点的旋转需要先平移 再旋转 再平移回去,涉及到齐次坐标,暂不讨论)。
定义二维空间中旋转角度为θ,根据三角函数的定义可知,基矢量x,y绕原点旋转后得到x丶,y丶如下图所示:

R(θ)=[cosθsinθ−sinθcosθ]
三维空间绕主轴线的旋转
和二维不同,三种中旋转是绕某个轴线进行的。本小节将介绍围绕主轴线(x,y,z)的旋转.
和缩放矩阵的推导类似,首先我们对三个基矢量进行变换,以围绕x轴旋转为例:
step1:对基矢量应用旋转变换:
x丶=x=⎣⎡100⎦⎤
y丶=⎣⎡0cosθsinθ⎦⎤
z丶=⎣⎡0−sinθcosθ⎦⎤
step2:组合基矢量形成旋转矩阵:
Rx(θ)=⎣⎡1000cosθsinθ0−sinθcosθ⎦⎤
同理可推导出沿y,z轴的旋转矩阵公式如下:
Ry(θ)=⎣⎡cosθ0−sinθ010sinθ0cosθ⎦⎤
Rz(θ)=⎣⎡cosθsinθ0−sinθcosθ0001⎦⎤
三维空间绕任意轴的旋转

让我们推导出一个围绕n^旋转θ角度的矩阵R(n^,θ),使得当矩阵R(n^,θ)乘以矢量v得到的矢量v丶是将v围绕n^旋转θ角度的结果.
v丶=R(n^,θ)v
推导思路
- 为了得到矩阵R(n^,θ),需要用v,n^,θ来表达v丶,基本思路是解决垂直于n^的平面中的问题,为此,将v分解为v∥和v⊥两个矢量,分别平行和垂直于单位矢量n^.通过单独旋转每个分量,剋将矢量作为一个整体旋转.即: v丶=v∥丶+v⊥丶.
- 由于v∥与n^平行,因此它不受旋转影响.即: v∥丶=v∥
- 根据矢量的投影计算可得: v∥=(v.n^)n^ v⊥=v−v∥
- 利用矢量叉积构造w: w=n^×v⊥=n^×v
- 注意上图所示,矢量w和v⊥构成了一个二维空间.v⊥作为x轴,w作为y轴.v⊥丶是在这个平面上按角度θ旋转v⊥的结果.
推导过程
v∥=(v.n^)n^
v⊥=v−v∥=v−(v.n^)n^
w=n^×v⊥=n^×v
v⊥丶=cosθv⊥+sinθw=cosθ(v−(v.n^)n^)+sinθ(n^×v)
v丶=v⊥丶+v∥=cosθ(v−(v.n^)n^)+sinθ(n^×v)+(v.n^)n^
接下来,计算变换后的基矢量.简单的带入上式即可.
x丶=⎣⎡nx2(1−cosθ)+cosθnxny(1−cosθ)+nzsinθnxnz(1−cosθ)−nysinθ⎦⎤
y丶=⎣⎡nxny(1−cosθ)−nzsinθny2(1−cosθ)+cosθnynz(1−cosθ)+nxsinθ⎦⎤
z丶=⎣⎡nxnz(1−cosθ)+nysinθnynz(1−cosθ)−nxsinθnz2(1−cosθ)+cosθ⎦⎤
通过变换后基矢量的简单组合,即可构造出旋转矩阵
R(n^,θ)=⎣⎡∣x丶∣∣y丶∣∣z丶∣⎦⎤=⎣⎡nx2(1−cosθ)+cosθnxny(1−cosθ)+nzsinθnxnz(1−cosθ)−nysinθnxny(1−cosθ)−nzsinθny2(1−cosθ)+cosθnynz(1−cosθ)+nxsinθnxnz(1−cosθ)+nysinθnynz(1−cosθ)−nxsinθnz2(1−cosθ)+cosθ⎦⎤.
至此绕任意轴的三维旋转矩阵推导完毕.
引用
《3D数学基础》图形和游戏开发(第二版)
GAMES101 -现代计算机图形学入门-闫令琪
scratchapixel