图形学的数学基础(八):矩阵线性变换

924 阅读4分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

图形学的数学基础(八):矩阵线性变换

我们可以通过添加一些值到它的坐标来平移一个点。 我们还可以利用三角函数来旋转矢量。 简而言之,矩阵只是将所有这些变换(缩放、旋转、反射、错切、平移)组合成一个单一结构的一种方式。 通过矩阵的方式我们可以方便的对空间中的点或矢量进行变换,而不用写一大堆的公式。这就是矩阵为何在图形渲染管线中存在重要意义的原因。图形中的任意变换都可以通过一个矩阵完成。 对同一个对象的多次变换可以通过矩阵乘积转换为单个矩阵。如下图:

注:本文所有推导和公式均使用列矢量形式。

1661828278234.jpg

线性变换

缩放(Scale)

沿主轴缩放

最简单的缩放是沿每个轴线应用单独的或者统一的缩放。

均匀缩放

保留原始对象的角度和比例, 使被缩放对象统一增大或者减少s因子。

1661829932657.jpg

[xy]=[S00S][xy]\begin{bmatrix}x^丶\\y^丶\end{bmatrix} = \begin{bmatrix}S&0\\0&S\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}

同理三维空间中采用以下形式:

[xyz]=[S000S000S][xyz]\begin{bmatrix}x^丶\\y^丶\\z^丶\end{bmatrix} = \begin{bmatrix}S&0&0\\0&S&0\\0&0&S\end{bmatrix}\begin{bmatrix}x\\y\\z\end{bmatrix}

非均匀缩放

如果希望"拉伸"或者"挤压"对象,则可以在不同方向上应用不同的缩放因子,这样会导致非均匀缩放。非均匀缩放不会保留原始对象的角度。

1661831020588.jpg

[xy]=[Sx00Sy][xy]\begin{bmatrix}x^丶\\y^丶\end{bmatrix} = \begin{bmatrix}S_x&0\\0&S_y\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}

同理三维空间中采用以下形式:

[xyz]=[Sx000Sy000Sz][xyz]\begin{bmatrix}x^丶\\y^丶\\z^丶\end{bmatrix} = \begin{bmatrix}S_x&0&0\\0&S_y&0\\0&0&S_z\end{bmatrix}\begin{bmatrix}x\\y\\z\end{bmatrix}

任意方向缩放

除了沿主轴线缩放外,还可以应用独立于坐标系的缩放,即沿任意方向的缩放。设n^\hat{n}缩放方向(缩放沿着n^\hat{n}执行),缩放因子s。以下将逐步实现沿任意方向缩放的方法。

step1: 推导表达式,给定任意矢量v\mathbf{v},用v,s,n^\mathbf{v},s,\hat{n}计算v\mathbf{v^丶}。基本思路是将矢量v\mathbf{v}n^\hat{n}上投影,分解为vv\vec{v_∥}和\vec{v_⊥}。其中v\vec{v_∥}根据k因子缩放,v\vec{v_⊥}保持不变。以下为推导过程:

1661840891822.png

v=v+v\vec{v} = \vec{v_∥} + \vec{v_⊥}

v=(v.n^)n^\vec{v_∥} = (\vec{v}.\hat{n})\hat{n}

v=v=vv=v(v.n^)n^\vec{v^丶_⊥} = \vec{v_⊥} = \vec{v} - \vec{v_∥} = \vec{v} - (\vec{v}.\hat{n})\hat{n}

v=sv=s(v.n^)n^\vec{v^丶_∥} = s\vec{v_∥} = s(\vec{v}.\hat{n})\hat{n}

v=v+v=v(v.n^)n^+s(v.n^)n^=v+(s1)(v.n^)n^\vec{v^丶} = \vec{v^丶_⊥} + \vec{v^丶_∥} = \vec{v} - (\vec{v}.\hat{n})\hat{n} + s(\vec{v}.\hat{n})\hat{n} = \vec{v} + (s-1)(\vec{v}.\hat{n})\hat{n}

step2: 既然我们知道了如何缩放任意矢量,则可以计算出缩放后的基矢量值,将原始基矢量x=[10],y=[01]x = \begin{bmatrix}1\\0\end{bmatrix},y = \begin{bmatrix}0\\1\end{bmatrix}带入上式可得:

x=x+(s1)(x.n^)n^=[10]+(s1)([10].[nxny]).[nxny]=[10]+(s1)nx.[nxny]=[1+(s1)nx2(s1)nxny]\vec{x^丶} = \vec{x} + (s-1)(\vec{x}.\hat{n})\hat{n}\\\quad\quad= \begin{bmatrix}1\\0\end{bmatrix} + (s-1)(\begin{bmatrix}1\\0\end{bmatrix}.\begin{bmatrix}n_x\\n_y\end{bmatrix}).\begin{bmatrix}n_x\\n_y\end{bmatrix} \\\quad\quad= \begin{bmatrix}1\\0\end{bmatrix} + (s-1)n_x.\begin{bmatrix}n_x\\n_y\end{bmatrix} \\\quad\quad= \begin{bmatrix}1 + (s-1){n_x}^2\\(s-1)n_xn_y\end{bmatrix}

y=[(s1)nxny1+(s1)(ny)2]\vec{y^丶} = \begin{bmatrix}(s-1)n_xn_y\\1 + (s-1)(n_y)^2\end{bmatrix}

推导出二维和三维矢量空间沿任意方向n^\hat{n}缩放s的矩阵为:

Scale2(n^,s)=[1+(s1)(nx)2(s1)nxny(s1)nxny1+(s1)ny2]\textbf{Scale}^2(\hat{n},s) = \begin{bmatrix}1 + (s-1)(n_x)^2&&(s-1)n_xn_y\\(s-1)n_xn_y&&1+(s-1){n_y}^2\end{bmatrix}

Scale3(n^,s)=[1+(s1)(nx)2(s1)nxny(s1)nxnz(s1)nxny1+(s1)ny2(s1)nynz(s1)nxnz(s1)nynz1+(s1)nz2]\textbf{Scale}^3(\hat{n},s) = \begin{bmatrix}1 + (s-1)(n_x)^2&&(s-1)n_xn_y&&(s-1)n_xn_z\\(s-1)n_xn_y&&1+(s-1){n_y}^2&&(s-1)n_yn_z\\(s-1)n_xn_z&&(s-1)n_yn_z&&1+(s-1){n_z}^2\end{bmatrix}

反射(Reflection)

反射其实是一种特殊的缩放,即按照某个轴线执行-1缩放。

沿主轴线的反射

reflection.png [xy]=[1001][xy]\begin{bmatrix}x^丶\\y^丶\end{bmatrix} = \begin{bmatrix}-1&0\\0&1\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}

沿任意轴反射

根据沿任意轴缩放得到的矩阵公式,将-1带入,可得沿任意轴反射的矩阵公式:

Reflection2(n^)=[1+(11)(nx)2(11)nxny(11)nxny1+(11)ny2]\textbf{Reflection}^2(\hat{n}) = \begin{bmatrix}1 + (-1-1)(n_x)^2&&(-1-1)n_xn_y\\(-1-1)n_xn_y&&1+(-1-1){n_y}^2\end{bmatrix}

Reflection3(n^)=[1+(11)(nx)2(11)nxny(11)nxnz(11)nxny1+(11)ny2(11)nynz(11)nxnz(11)nynz1+(11)nz2]\textbf{Reflection}^3(\hat{n}) = \begin{bmatrix}1 + (-1-1)(n_x)^2&&(-1-1)n_xn_y&&(-1-1)n_xn_z\\(-1-1)n_xn_y&&1+(-1-1){n_y}^2&&(-1-1)n_yn_z\\(-1-1)n_xn_z&&(-1-1)n_yn_z&&1+(-1-1){n_z}^2\end{bmatrix}

错切(Shaearing)

错切是一种“倾斜”坐标空间的变形。它将不均匀的拉伸空间,不保留角度。但是保留面积和体积。基本思路是将一个坐标的倍数添加到另一个坐标上。 shearing.jpg

[xy]=[1a01][xy]\begin{bmatrix}x^丶\\y^丶\end{bmatrix} = \begin{bmatrix}1&a\\0&1\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}

二维错切矩阵公式:

Hx(s)=[1s01]\textbf{H}_x(s) = \begin{bmatrix}1&s\\0&1\end{bmatrix} (沿x轴方向拉拽)

Hy(s)=[10s1]\textbf{H}_y(s) = \begin{bmatrix}1&0\\s&1\end{bmatrix} (沿y轴方向拉拽)

三维错切矩阵公式:

Hxy(s,t)=[100010st1]\textbf{H}_{xy}(s,t) = \begin{bmatrix}1&0&0\\0&1&0\\s&t&1\end{bmatrix}

Hxz(s,t)=[100s1tst1]\textbf{H}_{xz}(s,t) = \begin{bmatrix}1&0&0\\s&1&t\\s&t&1\end{bmatrix}

Hyz(s,t)=[1st010st1]\textbf{H}_{yz}(s,t) = \begin{bmatrix}1&s&t\\0&1&0\\s&t&1\end{bmatrix}

旋转(Rotation)

二维空间绕原点的旋转

在二维空间中只能绕点旋转,本小节公式和实例将旋转点限定为坐标系原点(绕任意点的旋转需要先平移 再旋转 再平移回去,涉及到齐次坐标,暂不讨论)。 定义二维空间中旋转角度为θ\theta,根据三角函数的定义可知,基矢量x,y\vec{x},\vec{y}绕原点旋转后得到x,y\vec{x^丶},\vec{y^丶}如下图所示:

rotation2d.png

R(θ)=[cosθsinθsinθcosθ]\textbf{R}(\theta) = \begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}

三维空间绕主轴线的旋转

和二维不同,三种中旋转是绕某个轴线进行的。本小节将介绍围绕主轴线(xyz\mathbf{x},\mathbf{y},\mathbf{z})的旋转. 和缩放矩阵的推导类似,首先我们对三个基矢量进行变换,以围绕x\mathbf{x}轴旋转为例:

step1:对基矢量应用旋转变换:

x=x=[100]\mathbf{x^丶} = \mathbf{x} = \begin{bmatrix}1\\0\\0\end{bmatrix}

y=[0cosθsinθ]\mathbf{y^丶} = \begin{bmatrix}0\\\cos\theta\\\sin\theta\end{bmatrix}

z=[0sinθcosθ]\mathbf{z^丶} = \begin{bmatrix}0\\-\sin\theta\\\cos\theta\end{bmatrix}

step2:组合基矢量形成旋转矩阵:

Rx(θ)=[1000cosθsinθ0sinθcosθ]\textbf{R}_x(\theta) = \begin{bmatrix}1&0&0\\0&\cos\theta&-\sin\theta\\0&\sin\theta&\cos\theta\end{bmatrix}

同理可推导出沿y,z\mathbf{y},\mathbf{z}轴的旋转矩阵公式如下:

Ry(θ)=[cosθ0sinθ010sinθ0cosθ]\textbf{R}_y(\theta) = \begin{bmatrix}\cos\theta&0&\sin\theta\\0&1&0\\-\sin\theta&0&\cos\theta\end{bmatrix}

Rz(θ)=[cosθsinθ0sinθcosθ0001]\textbf{R}_z(\theta) = \begin{bmatrix}\cos\theta&-\sin\theta&0\\\sin\theta&\cos\theta&0\\0&0&1\end{bmatrix}

三维空间绕任意轴的旋转

1661866156316.jpg

让我们推导出一个围绕n^\hat{n}旋转θ\theta角度的矩阵R(n^,θ)\textbf{R}(\hat{n},\theta),使得当矩阵R(n^,θ)\textbf{R}(\hat{n},\theta)乘以矢量v\mathbf{v}得到的矢量v\mathbf{v^丶}是将v\mathbf{v}围绕n^\hat{n}旋转θ\theta角度的结果.

v=R(n^,θ)v\mathbf{v^丶} = \textbf{R}(\hat{n},\theta)\mathbf{v}

推导思路

  1. 为了得到矩阵R(n^,θ)\textbf{R}(\hat{n},\theta),需要用v,n^,θ\mathbf{v}, \hat{n}, \theta来表达v\mathbf{v^丶},基本思路是解决垂直于n^\hat{n}的平面中的问题,为此,将v\mathbf{v}分解为vv\mathbf{v_∥}和\mathbf{v_⊥}两个矢量,分别平行和垂直于单位矢量n^\hat{n}.通过单独旋转每个分量,剋将矢量作为一个整体旋转.即: v=v+v\mathbf{v^丶} = \mathbf{v_∥^丶} + \mathbf{v_⊥^丶}.
  2. 由于v\mathbf{v_∥}n^\hat{n}平行,因此它不受旋转影响.即: v=v\mathbf{v^丶_∥} = \mathbf{v_∥}
  3. 根据矢量的投影计算可得: v=(v.n^)n^\mathbf{v_∥} = (\mathbf{v}.\hat{n})\hat{n} v=vv\mathbf{v_⊥} = \mathbf{v} - \mathbf{v_∥}
  4. 利用矢量叉积构造w\mathbf{w}: w=n^×v=n^×v\mathbf{w} = \hat{n}\times\mathbf{v_⊥} = \hat{n}\times\mathbf{v}
  5. 注意上图所示,矢量wv\mathbf{w}和\mathbf{v_⊥}构成了一个二维空间.v\mathbf{v_⊥}作为x轴,w\mathbf{w}作为y轴.v\mathbf{v^丶_⊥}是在这个平面上按角度θ\theta旋转v\mathbf{v_⊥}的结果.

推导过程

v=(v.n^)n^\mathbf{v_∥} = (\mathbf{v}.\hat{n})\hat{n}

v=vv=v(v.n^)n^\mathbf{v_⊥} = \mathbf{v} - \mathbf{v_∥} = \mathbf{v} - (\mathbf{v}.\hat{n})\hat{n}

w=n^×v=n^×v\mathbf{w} = \hat{n}\times\mathbf{v_ ⊥} = \hat{n}\times\mathbf{v}

v=cosθv+sinθw=cosθ(v(v.n^)n^)+sinθ(n^×v)\mathbf{v^丶_⊥} = \cos\theta\mathbf{v_⊥} + \sin\theta\mathbf{w} = \cos\theta(\mathbf{v} - (\mathbf{v}.\hat{n})\hat{n}) + \sin\theta(\hat{n}\times\mathbf{v})

v=v+v=cosθ(v(v.n^)n^)+sinθ(n^×v)+(v.n^)n^\mathbf{v^丶} = \mathbf{v^丶_⊥} + \mathbf{v_∥} = \cos\theta(\mathbf{v} - (\mathbf{v}.\hat{n})\hat{n}) + \sin\theta(\hat{n}\times\mathbf{v}) + (\mathbf{v}.\hat{n})\hat{n}

接下来,计算变换后的基矢量.简单的带入上式即可.

x=[nx2(1cosθ)+cosθnxny(1cosθ)+nzsinθnxnz(1cosθ)nysinθ]\mathbf{x^丶} = \begin{bmatrix}{n_x}^2(1-\cos\theta) + \cos\theta\\{n_x}{n_y}(1-\cos\theta)+{n_z}\sin\theta\\{n_x}{n_z}(1-\cos\theta)-{n_y}\sin\theta\end{bmatrix}

y=[nxny(1cosθ)nzsinθny2(1cosθ)+cosθnynz(1cosθ)+nxsinθ]\mathbf{y^丶} = \begin{bmatrix}{n_x}{n_y}(1-\cos\theta) - {n_z}\sin\theta\\{n_y}^2(1-\cos\theta)+\cos\theta\\{n_y}{n_z}(1-\cos\theta)+{n_x}\sin\theta\end{bmatrix}

z=[nxnz(1cosθ)+nysinθnynz(1cosθ)nxsinθnz2(1cosθ)+cosθ]\mathbf{z^丶} = \begin{bmatrix}{n_x}{n_z}(1-\cos\theta) + {n_y}\sin\theta\\{n_y}{n_z}(1-\cos\theta)-{n_x}\sin\theta\\{n_z}^2(1-\cos\theta)+\cos\theta\end{bmatrix}

通过变换后基矢量的简单组合,即可构造出旋转矩阵

R(n^,θ)=[xyz]=[nx2(1cosθ)+cosθnxny(1cosθ)nzsinθnxnz(1cosθ)+nysinθnxny(1cosθ)+nzsinθny2(1cosθ)+cosθnynz(1cosθ)nxsinθnxnz(1cosθ)nysinθnynz(1cosθ)+nxsinθnz2(1cosθ)+cosθ]\textbf{R}(\hat{n},\theta) = \begin{bmatrix}|&|&|\\\mathbf{x^丶}&\mathbf{y^丶}&\mathbf{z^丶}\\|&|&|\end{bmatrix} = \begin{bmatrix}{n_x}^2(1-\cos\theta) + \cos\theta&{n_x}{n_y}(1-\cos\theta) - {n_z}\sin\theta&{n_x}{n_z}(1-\cos\theta) + {n_y}\sin\theta\\{n_x}{n_y}(1-\cos\theta)+{n_z}\sin\theta&{n_y}^2(1-\cos\theta)+\cos\theta&{n_y}{n_z}(1-\cos\theta)-{n_x}\sin\theta\\{n_x}{n_z}(1-\cos\theta)-{n_y}\sin\theta&{n_y}{n_z}(1-\cos\theta)+{n_x}\sin\theta&{n_z}^2(1-\cos\theta)+\cos\theta\end{bmatrix}.

至此绕任意轴的三维旋转矩阵推导完毕.

引用

《3D数学基础》图形和游戏开发(第二版)

GAMES101 -现代计算机图形学入门-闫令琪

scratchapixel