熙妍和小猕猴桃 發表於 2025-6-5 00:15:00

《Fundamentals of Computer Graphics》第七章 矩阵变换

<h1 id="开篇">开篇</h1>
<p>  线性代数的机制可以被用来表达排布三维场景中的物体、使用相机观察物体、在屏幕上看到物体所需要的许多操作。<strong>几何变换</strong>(<strong>Geometric Transformation</strong>)例如旋转、平移、缩放、投影都可以通过与矩阵相乘来得到,<strong>变换矩阵</strong>(<strong>Transformation Matrices</strong>)就是这章的话题。</p>
<h1 id="二维线性变换2d-linear-transformations">二维线性变换(2D Linear Transformations)</h1>
<p>  我们可以使用一个<span class="math inline">\(2 \times 2\)</span>的矩阵来改变或变换一个二维向量</p>
<p></p><div class="math display">\[\begin{bmatrix} a_{11} &amp; a_{12} \\ a_{21} &amp; a_{22} \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} a_{11}x+a_{12}y \\ a_{21}x+a_{22}y \end{bmatrix}
\]</div><p></p><p>这种简单的取一个二维向量产生另外一个向量的矩阵乘法,就叫做<strong>线性变换</strong>(<strong>Linear Transformation</strong>),使用这种简单的公式可以达到许多不同类型的有用的变换。</p>
<h2 id="缩放scaling">缩放(Scaling)</h2>
<p>  最基础的变换就是沿坐标轴<strong>缩放</strong>(<strong>Scale</strong>),这种变换可以改变模而且有可能改变方向。</p>
<p></p><div class="math display">\[\mathrm{scale}(s_x,s_y)=\begin{bmatrix} s_x &amp; 0 \\ 0 &amp; s_y \end{bmatrix}
\]</div><p></p><p></p><div class="math display">\[\begin{bmatrix} s_x &amp; 0 \\ 0 &amp; s_y \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} s_xx \\ x_yy \end{bmatrix}
\]</div><p></p><p>下面是两个缩放的例子</p>
<p></p><div class="math display">\[\mathrm{scale}(0.5,0.5) = \begin{bmatrix} 0.5 &amp; 0 \\ 0 &amp; 0.5 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604000229657-1106985474.png"></p>
<p></p><div class="math display">\[\mathrm{scale}(0.5,1.5) = \begin{bmatrix} 0.5 &amp; 0 \\ 0 &amp; 1.5 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604000331634-1754431661.png"></p>
<h2 id="剪切shearing">剪切(Shearing)</h2>
<p>  剪切描述的是把东西推向某边的那种变换,水平剪切矩阵和竖直剪切矩阵长这样</p>
<p></p><div class="math display">\[\mathrm{shear-x}(s)=\begin{bmatrix} 1 &amp; s \\ 0 &amp; 1 \end{bmatrix},\mathrm{shear-y}(s)=\begin{bmatrix} 1 &amp; 0 \\ s &amp; 1 \end{bmatrix}
\]</div><p></p><p>下面是两个剪切的例子</p>
<p></p><div class="math display">\[\mathrm{shear-x}(1)=\begin{bmatrix} 1 &amp; 1 \\ 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604001738189-1078272291.png"></p>
<p></p><div class="math display">\[\mathrm{shear-y}(1)=\begin{bmatrix} 1 &amp; 0 \\ 1 &amp; 1 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604001831624-682321046.png"></p>
<h2 id="旋转rotation">旋转(Rotation)</h2>
<p>  假设我们想以一个<span class="math inline">\(\phi\)</span>角度逆时针旋转向量<span class="math inline">\(\mathbf{a}\)</span>到向量<span class="math inline">\(\mathbf{b}\)</span>,我们首先用半径<span class="math inline">\(r\)</span>和角度<span class="math inline">\(\alpha\)</span>来表示向量<span class="math inline">\(\mathbf{a}\)</span></p>
<p></p><div class="math display">\[x_a=r\cos\alpha
\]</div><p></p><p></p><div class="math display">\[y_a=r\sin\alpha
\]</div><p></p><p>因为<span class="math inline">\(\mathbf{b}\)</span>是从<span class="math inline">\(\mathbf{a}\)</span>旋转得到的,因此可得</p>
<p></p><div class="math display">\[x_b=r\cos(\alpha+\phi)=r\cos\alpha\cos\phi-r\sin\alpha\sin\phi
\]</div><p></p><p></p><div class="math display">\[y_b=r\sin(\alpha+\phi)=r\sin\alpha\cos\phi+r\cos\alpha\sin\phi
\]</div><p></p><p>因为<span class="math inline">\(x_a=r\cos\alpha\)</span>、<span class="math inline">\(y_a=r\sin\alpha\)</span>,这实际上等于</p>
<p></p><div class="math display">\[x_b=x_a\cos\phi-y_a\sin\phi
\]</div><p></p><p></p><div class="math display">\[y_b=y_a\cos\phi+x_a\sin\phi
\]</div><p></p><p>可以化成矩阵向量相乘形式</p>
<p></p><div class="math display">\[\begin{bmatrix} x_b \\ y_b \end{bmatrix} = \begin{bmatrix} \cos\phi &amp; -\sin\phi \\ \sin\phi &amp; \cos\phi \end{bmatrix} \begin{bmatrix} x_a \\ y_a \end{bmatrix}
\]</div><p></p><p>因此旋转矩阵为</p>
<p></p><div class="math display">\[\mathrm{rotate}(\phi) = \begin{bmatrix} \cos\phi &amp; -\sin\phi \\ \sin\phi &amp; \cos\phi \end{bmatrix}
\]</div><p></p><p>下面是两个旋转的例子</p>
<p></p><div class="math display">\[\begin{bmatrix} \cos\frac{\pi}{4} &amp; -\sin\frac{\pi}{4} \\ \sin\frac{\pi}{4} &amp; \cos\frac{\pi}{4} \end{bmatrix} = \begin{bmatrix} 0.707 &amp; -0.707 \\ 0.707 &amp; 0.707 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604003337719-2114254935.png"></p>
<p></p><div class="math display">\[\begin{bmatrix} \cos\frac{-\pi}{6} &amp; -\sin\frac{-\pi}{6} \\ \sin\frac{-\pi}{6} &amp; \cos\frac{-\pi}{6} \end{bmatrix} = \begin{bmatrix} 0.866 &amp; 0.5 \\ -0.5 &amp; 0.866 \end{bmatrix}
\]</div><p></p><p><img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604003458202-1389701616.png"></p>
<h2 id="反射reflection">反射(Reflection)</h2>
<p>  我们可以让向量沿着坐标轴反射,沿<span class="math inline">\(y\)</span>轴反射和沿<span class="math inline">\(x\)</span>轴反射的矩阵为</p>
<p></p><div class="math display">\[\mathrm{reflect-y}=\begin{bmatrix} -1 &amp; 0 \\ 0 &amp; 1 \end{bmatrix},\mathrm{reflect-x}=\begin{bmatrix} 1 &amp; 0 \\ 0 &amp; -1 \end{bmatrix}
\]</div><p></p><p>下面是两个反射的例子<br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604004521379-1398523003.png"><br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604004531341-1441939789.png"></p>
<p>要注意的是,叠加这两种反射等效于旋转<span class="math inline">\(\pi\)</span>弧度。</p>
<h2 id="变换的合成和分解composition-and-decomposition-of-transformations">变换的合成和分解(Composition and Decomposition of Transformations)</h2>
<p>  对于图形程序来说施加多个变换是很常见的,例如首先施加缩放<span class="math inline">\(\mathbf{S}\)</span>接着施加旋转<span class="math inline">\(\mathbf{R}\)</span>,可以通过两步做到</p>
<p></p><div class="math display">\[\mathbf{v}_2=\mathbf{S}\mathbf{v}_1,\mathbf{v}_3=\mathbf{R}\mathbf{v}_2
\]</div><p></p><p>另一个方法是</p>
<p></p><div class="math display">\[\mathbf{v}_3 =\mathbf{R}(\mathbf{Sv}_1)
\]</div><p></p><p>因为矩阵相乘服从结合律我们也可以这么写</p>
<p></p><div class="math display">\[\mathbf{v}_3 = (\mathbf{RS})\mathbf{v}_1
\]</div><p></p><p>这样我们可以得到一个新的矩阵<span class="math inline">\(\mathbf{M}=\mathbf{RS}\)</span>,这个新的矩阵描述的就是先缩放再旋转的变换。下图是个相关的例子<br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604010308320-1606838858.png"></p>
<p>之前提到过矩阵相乘不服从交换律,下图是个相关的例子<br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604010458614-1906919093.png"></p>
<h2 id="变换的分解decomposition-of-transformations">变换的分解(Decomposition of Transformations)</h2>
<p>  有时候需要撤销变换,把变换分成更简单的片段。例如,让用户控制旋转因子和缩放因子来向其展示变换。但是在内部,变换可能仅仅使用一个矩阵来表达,而这个矩阵已经混合好了旋转和缩放。其实可以通过先把矩阵拆解成期望的片段,接着调整这些片段,最后再次组装这些变换得到。<br>
  对于对称矩阵来说有特征值分解,可以把对称矩阵<span class="math inline">\(\mathbf{A}\)</span>分解成如下形式</p>
<p></p><div class="math display">\[\mathbf{A}=\mathbf{RSR}^\mathrm{T}
\]</div><p></p><p>式中的<span class="math inline">\(\mathbf{R}\)</span>为正交矩阵,<span class="math inline">\(\mathbf{S}\)</span>为对角矩阵。从几何角度来理解,可以把<span class="math inline">\(\mathbf{R}\)</span>当作旋转,把<span class="math inline">\(\mathbf{S}\)</span>当作缩放,实际上就是把单步变换<span class="math inline">\(\mathbf{A}\)</span>变成了多步变换<span class="math inline">\(\mathbf{RSR}^\mathrm{T}\)</span>。令特征向量为<span class="math inline">\(\mathbf{v}_1\)</span>和<span class="math inline">\(\mathbf{v}_2\)</span>,特征值为<span class="math inline">\(\lambda_1\)</span>和<span class="math inline">\(\lambda_2\)</span>,<span class="math inline">\(\mathbf{RSR}^\mathrm{T}\)</span>代表的多步变换可以被解释为<br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604152049950-501113689.png"></p>
<p>  对于非对称矩阵来说有奇异值分解,可以把非对称矩阵<span class="math inline">\(\mathbf{A}\)</span>分解成如下形式</p>
<p></p><div class="math display">\[\mathbf{A}=\mathbf{USV}^\mathrm{T}
\]</div><p></p><p>式中的<span class="math inline">\(\mathbf{U}\)</span>和<span class="math inline">\(\mathbf{V}\)</span>为正交矩阵,<span class="math inline">\(\mathbf{S}\)</span>为对角矩阵。从几何的角度来理解,可以把<span class="math inline">\(\mathbf{U}\)</span>和<span class="math inline">\(\mathbf{V}\)</span>当作旋转,把<span class="math inline">\(\mathbf{S}\)</span>当作缩放。令左奇异向量为<span class="math inline">\(\mathbf{u}_1\)</span>和<span class="math inline">\(\mathbf{u}_2\)</span>,右奇异向量为<span class="math inline">\(\mathbf{v}_1\)</span>和<span class="math inline">\(\mathbf{v_2}\)</span>,奇异值为<span class="math inline">\(\sigma_1\)</span>和<span class="math inline">\(\sigma_2\)</span>,<span class="math inline">\(\mathbf{USV}^\mathrm{T}\)</span>代表的多步变换可以被解释为<br>
<img src="https://img2023.cnblogs.com/blog/2774734/202506/2774734-20250604155000493-262794390.png"><br>
  还有一种是用于非0旋转的Paeth分解,如下所示</p>
<p></p><div class="math display">\[\begin{bmatrix} \cos\phi &amp; -\sin\phi \\ \sin\phi &amp; \cos\phi \end{bmatrix} = \begin{bmatrix} 1 &amp; \frac{\cos\phi-1}{\sin\phi} \\ 0 &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; 0 \\ \sin\phi &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; \frac{\cos\phi-1}{\sin\phi} \\ 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p>以45°旋转为例可以得到</p>
<p></p><div class="math display">\[\mathrm{rotate}(\frac{\pi}{4})=\begin{bmatrix} 1 &amp; 1-\sqrt{2} \\ 0 &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; 0 \\ \frac{\sqrt{2}}{2} &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; 1-\sqrt{2} \\ 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p>这种特别的变换对光栅旋转非常有用,因为剪切是对图像非常有效的光栅操作,它会引入一些锯齿但是不会留下孔洞。一个关键的观察是,如果取光栅位置<span class="math inline">\((i,j)\)</span>接着施加水平剪切,我们可以得到</p>
<p></p><div class="math display">\[\begin{bmatrix} 1 &amp; s \\ 0 &amp; 1 \end{bmatrix} \begin{bmatrix} i \\ j \end{bmatrix} = \begin{bmatrix} i+sj \\ j \end{bmatrix}
\]</div><p></p><p>如果把<span class="math inline">\(sj\)</span>舍入到最近的整数,这个量会让每一行往侧边移动一点,行与行之间移动的量会相差一定量,但是相同行的每个位置往侧边移动的量是一样的,因此能让旋转后的图像的内部无孔洞。对于竖直剪切也是一样的道理,因此我们可以简单地实现一个光栅旋转。</p>
<h1 id="三维线性变换3d-linear-transformations">三维线性变换(3D Linear Transformations)</h1>
<p>三维线性变换可以从二维线性变换推广得到,例如沿轴缩放为</p>
<p></p><div class="math display">\[\mathrm{scale}(s_x,s_y,s_z)=\begin{bmatrix} s_x &amp; 0 &amp; 0 \\ 0 &amp; s_y &amp; 0 \\ 0 &amp; 0 &amp; s_z \end{bmatrix}
\]</div><p></p><p>三维中的旋转分为绕z、x、y轴旋转,分别为</p>
<p></p><div class="math display">\[\mathrm{rotate-z}(\phi)=\begin{bmatrix} \cos\phi &amp; -\sin\phi &amp; 0 \\ \sin\phi &amp; \cos\phi &amp; 0 \\ 0 &amp; 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p></p><div class="math display">\[\mathrm{rotate-x}(\phi)=\begin{bmatrix} 1 &amp; 0 &amp; 0 \\ 0 &amp; \cos\phi &amp; -\sin\phi \\ 0 &amp; \sin\phi &amp; \cos\phi \end{bmatrix}
\]</div><p></p><p></p><div class="math display">\[\mathrm{rotate-y}(\phi)=\begin{bmatrix} \cos\phi &amp; 0 &amp; \sin\phi \\ 0 &amp; 1 &amp; 0 \\ -\sin\phi &amp; 0 &amp; \cos\phi \end{bmatrix}
\]</div><p></p><p>在二维中的剪切可以沿着某个轴进行,而在三维中</p>
<p></p><div class="math display">\[\mathrm{shear-x}(d_x,d_z)=\begin{bmatrix} 1 &amp; d_x &amp; d_z \\ 0 &amp; 1 &amp; 0 \\ 0 &amp; 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p>和二维变换一样,三维变换矩阵也可以进行奇异值分解,从而得到一个旋转矩阵、一个缩放矩阵、另一个旋转矩阵。当然了,对称三维矩阵也可以使用特征值分解,从而得到一个旋转矩阵、一个缩放矩阵、一个逆旋转矩阵。此外,一个三维旋转矩阵也可以分解成三维剪切矩阵的乘积。</p>
<h2 id="任意三维旋转arbitrary-3d-rotations">任意三维旋转(Arbitrary 3D Rotations)</h2>
<p>  绕任意轴旋转其实很简单,可以利用上一章的对矩阵变换向量的不同理解得到。假设我们有一个点<span class="math inline">\((x,y,z)\)</span>处于全局坐标系中,想让点<span class="math inline">\((x,y,z)\)</span>绕<span class="math inline">\(\mathbf{w}\)</span>轴旋转,我们首先得找到另外两个辅助轴<span class="math inline">\(\mathbf{u}\)</span>和<span class="math inline">\(\mathbf{v}\)</span>,要求是<span class="math inline">\(\mathbf{u}\)</span>、<span class="math inline">\(\mathbf{v}\)</span>、<span class="math inline">\(\mathbf{w}\)</span>能组成一个规范正交基。有了这个条件后,我们先把点<span class="math inline">\((x,y,z)\)</span>投影到<span class="math inline">\(\{\mathbf{u},\mathbf{v},\mathbf{w}\}\)</span>这个坐标系中,于是可以使用这个矩阵</p>
<p></p><div class="math display">\[\begin{bmatrix} x_u &amp; y_u &amp; z_u \\ x_v &amp; y_v &amp; z_v \\ x_w &amp; y_w &amp; z_w \end{bmatrix}
\]</div><p></p><p>接着我们绕<span class="math inline">\(\{\mathbf{u},\mathbf{v},\mathbf{w}\}\)</span>这个坐标系中的z轴旋转,于是可以用这个矩阵</p>
<p></p><div class="math display">\[\mathrm{rotate-z}(\phi)=\begin{bmatrix} \cos\phi &amp; -\sin\phi &amp; 0 \\ \sin\phi &amp; \cos\phi &amp; 0 \\ 0 &amp; 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p>最后我们使用<span class="math inline">\(\mathbf{u}\)</span>、<span class="math inline">\(\mathbf{v}\)</span>、<span class="math inline">\(\mathbf{w}\)</span>这三个基向量,把在这个坐标系中绕z轴旋转后的坐标变换到全局坐标系中,从而得到点<span class="math inline">\((x,y,z)\)</span>绕<span class="math inline">\(\mathbf{w}\)</span>轴旋转后的点<span class="math inline">\((x^{new},y^{new},z^{new})\)</span>,因此可以使用这个矩阵</p>
<p></p><div class="math display">\[\begin{bmatrix} x_u &amp; x_v &amp; x_w \\ y_u &amp; y_v &amp; y_w \\ z_u &amp; z_v &amp; z_w \end{bmatrix}
\]</div><p></p><p>综上,绕轴多步变换为</p>
<p></p><div class="math display">\[\begin{bmatrix} x^{new} \\ y^{new} \\ z^{new} \end{bmatrix} = \begin{bmatrix} x_u &amp; x_v &amp; x_w \\ y_u &amp; y_v &amp; y_w \\ z_u &amp; z_v &amp; z_w \end{bmatrix} \begin{bmatrix} \cos\phi &amp; -\sin\phi &amp; 0 \\ \sin\phi &amp; \cos\phi &amp; 0 \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x_u &amp; y_u &amp; z_u \\ x_v &amp; y_v &amp; z_v \\ x_w &amp; y_w &amp; z_w \end{bmatrix} \begin{bmatrix} x \\ y \\ z \end{bmatrix}
\]</div><p></p><h2 id="变换法线transforming-normal-vectors">变换法线(Transforming Normal Vectors)</h2>
<p>  绝大多数三维向量都是用来表示位置或方向的,例如光从哪来。不过有些向量会被用来表示<strong>表面法线</strong>(<strong>Surface Normals</strong>),当表面被变换时这些法线不能以同样方式被变换。假设表面会被矩阵<span class="math inline">\(\mathbf{M}\)</span>变换,表面的切向向量<span class="math inline">\(\mathbf{t}\)</span>被<span class="math inline">\(\mathbf{M}\)</span>变换后会保持与表面相切。然而表面法线<span class="math inline">\(\mathbf{n}\)</span>被<span class="math inline">\(\mathbf{M}\)</span>变换后可能不会与表面垂直。因此我们得以<span class="math inline">\(\mathbf{M}\)</span>为基础,得到用于变换法线的矩阵<span class="math inline">\(\mathbf{N}\)</span>。因为表面的切向向量与表面法线总是垂直的,因此可以得到</p>
<p></p><div class="math display">\[\begin{align*}
\mathbf{n}^\mathrm{T}\mathbf{t}&amp;=0 \\
\mathbf{n}^\mathrm{T}\mathbf{I}\mathbf{t}&amp;=0 \\
\mathbf{n}^\mathrm{T}\mathbf{M}^{-1}\mathbf{M}\mathbf{t}&amp;=0
\end{align*}
\]</div><p></p><p>这两个向量被分别变换后也会保持垂直,因此</p>
<p></p><div class="math display">\[\begin{align*}
(\mathbf{Nn})^\mathrm{T}\mathbf{Mt}&amp;=0 \\
\mathbf{n}^\mathrm{T}\mathbf{N}^\mathrm{T}\mathbf{Mt}&amp;=0
\end{align*}
\]</div><p></p><p>由<span class="math inline">\(\mathbf{n}^\mathrm{T}\mathbf{M}^{-1}\mathbf{M}\mathbf{t}=0\)</span>和<span class="math inline">\(\mathbf{n}^\mathrm{T}\mathbf{N}^\mathrm{T}\mathbf{Mt}=0\)</span>可以得到<span class="math inline">\(\mathbf{N}^\mathrm{T}=\mathbf{M}^{-1}\)</span>,所以</p>
<p></p><div class="math display">\[\mathbf{N}=(\mathbf{M}^{-1})^\mathrm{T}或\mathbf{N}=(\mathbf{M}^\mathrm{T})^{-1}
\]</div><p></p><h1 id="平移和仿射变换translation-and-affine-transformations">平移和仿射变换(Translation and Affine Transformations)</h1>
<p>之前已经探讨过了使用矩阵来进行缩放、旋转、剪切等变换,在二维中变换为</p>
<p></p><div class="math display">\[\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} = \begin{bmatrix} m_{11} &amp; m_{12} \\ m_{21} &amp; m_{22} \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix}
\]</div><p></p><p>这种变换有个缺点,就是不能<strong>移动</strong>物体,只能进行缩放、旋转等变换。为了让物体<strong>平移</strong>(<strong>Translate</strong>),我们必须实现这样一种变换</p>
<p></p><div class="math display">\[\begin{align*}
x^{\prime} &amp;= x + x_t \\
y^{\prime} &amp;= y + y_t
\end{align*}
\]</div><p></p><p>结果很简单,我们为表示位置的点<span class="math inline">\((x,y)\)</span>增加一个坐标到<span class="math inline">\((x,y,1)\)</span>接着与下面这种<span class="math inline">\(3 \times 3\)</span>的矩阵相乘</p>
<p></p><div class="math display">\[\begin{bmatrix} m_{11} &amp; m_{12} &amp; x_t \\ m_{21} &amp; m_{22} &amp; y_t \\ 0 &amp; 0 &amp; 1 \end{bmatrix}
\]</div><p></p><p>相乘的结果为</p>
<p></p><div class="math display">\[\begin{bmatrix} x^{\prime} \\ y^{\prime} \\ 1 \end{bmatrix} = \begin{bmatrix} m_{11} &amp; m_{12} &amp; x_t \\ m_{21} &amp; m_{22} &amp; y_t \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \end{bmatrix} \equiv \begin{bmatrix} m_{11}x+m_{12}y+x_t \\ m_{21}x+m_{22}y+y_t \\ 1 \end{bmatrix}
\]</div><p></p><p>这一个矩阵就实现了一次线性变换加上一次平移变换,这种类型的变换叫做<strong>仿射变换</strong>(<strong>Affine Transformation</strong>),为实现仿射变换而增加的那一个维度的坐标叫做<strong>齐次坐标</strong>(<strong>Homogeneous Coordinate</strong>)。<br>
  要注意的是,这种变换会带来一个问题,使表示方向的向量平移是明显不合理的,可以把齐次坐标置零来解决这个问题</p>
<p></p><div class="math display">\[\begin{bmatrix} 1 &amp; 0 &amp; x_t \\ 0 &amp; 1 &amp; y_t \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 0 \end{bmatrix}
\]</div><p></p><p>在之后的章节,我们会实现透视视图,到那个时候会了解齐次坐标的其它用途。特别地来说,齐次坐标是在图形硬件中实现的渲染器的设计和操作的基石。在三维中的平移和二维中的差不多,增加一个第四坐标即可,因此三维中的平移变换为</p>
<p></p><div class="math display">\[\begin{bmatrix} 1 &amp; 0 &amp; 0 &amp; x_t \\ 0 &amp; 1 &amp; 0 &amp; y_t \\ 0 &amp; 0 &amp; 1 &amp; z_t \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} = \begin{bmatrix} x+x_t \\ y+y_t \\ z+z_t \\ 1 \end{bmatrix}
\]</div><p></p><p>这里要再次注意把表示方向的向量的齐次坐标置零。</p>
<h1 id="逆变换矩阵inverses-of-transformation-matrices">逆变换矩阵(Inverses of Transformation Matrices)</h1>
<p>  有时我们可能想进行逆变换,例如对于缩放<span class="math inline">\(\mathrm{scale}(s_x,s_y,s_z)\)</span>的逆缩放就是<span class="math inline">\(\mathrm{scale}(1/s_x,1/s_y,1/s_z)\)</span>,旋转的逆就是反方向旋转,平移的逆就是反方向平移。如果我们有一些矩阵<span class="math inline">\(\mathbf{M}=\mathbf{M}_1\mathbf{M}_2\cdots\mathbf{M}_n\)</span>,它的逆变换就是<span class="math inline">\(\mathbf{M}^{-1}=\mathbf{M}^{-1}_n\cdots\mathbf{M}^{-1}_2\mathbf{M}^{-1}_1\)</span>。<br>
  当然了,我们也可以用奇异值分解来求逆变换,对于上面的矩阵<span class="math inline">\(\mathbf{M}\)</span>有</p>
<p></p><div class="math display">\[\mathbf{M}=\mathbf{R}_1\mathrm{scale}(\sigma_1,\sigma_2,\sigma_3)\mathbf{R}_2
\]</div><p></p><p>因此它的逆变换<span class="math inline">\(\mathbf{M}^{-1}\)</span>为</p>
<p></p><div class="math display">\[\mathbf{M}^{-1}=\mathbf{R}^{\mathrm{T}}_2\mathrm{scale}(1/\sigma_1,1/\sigma_2,1/\sigma_3)\mathbf{R}^{\mathrm{T}}_1
\]</div><p></p><h1 id="坐标变换coordinate-transformations">坐标变换(Coordinate Transformations)</h1>
<p>  之前的所有讨论都是使用矩阵来变换一些点,不过这还隐藏着其它含义,其实我们也可以把它们看成是在改变坐标系统。例如坐在行进的车中观察,这个时候会发现车之外的物体都在相对你往后移动,从计算机和变换的角度来理解,就是每帧都有变换矩阵作用于物体来让其往后移动。从另一个方面来说,感受到相对移动实际上是以你的视角为参考的结果。这个时候就发现了变换矩阵和改变坐标系统实际上是息息相关的。<br>
  从几何上说,一个坐标系统或坐标帧是由原点和基构成的,规范正交基是最常用的一种。在一帧中,坐标系统的原点和基分别为<span class="math inline">\(\mathbf{p}\)</span>和<span class="math inline">\(\{\mathbf{u},\mathbf{v},\mathbf{w}\}\)</span>,我们可以用在这个坐标系中的一点<span class="math inline">\((u,v,w)\)</span>得到另外一点</p>
<p></p><div class="math display">\[\mathbf{p}+u\mathbf{u}+v\mathbf{v}+w\mathbf{w}
\]</div><p></p><p>在计算机中存储这些向量时,会发现这些向量实际上是在某个坐标系统中表达的,例如坐标系原点<span class="math inline">\(\mathbf{p}\)</span>实际上是位于某个坐标系统中的。为了让这一切进行下去,我们需要指定规范坐标系统,通常叫“全局”或“世界”坐标系统,这种系统会被用来描述其它所有系统。<br>
  在二维中,规范坐标系统通常用点<span class="math inline">\(\mathbf{o}\)</span>表示原点,用<span class="math inline">\(\mathbf{x}\)</span>和<span class="math inline">\(\mathbf{y}\)</span>来表示右手规范正交基向量。其它的坐标系统可能用<span class="math inline">\(\mathbf{e}\)</span>来表示原点,用<span class="math inline">\(\mathbf{u}\)</span>和<span class="math inline">\(\mathbf{v}\)</span>来表示右手规范正交基向量。一般来说,用于描述规范坐标系统的数据是不需要被显式存储的,因为它们是其它所有坐标系统的参考。使用规范坐标系中的坐标<span class="math inline">\((x_p,y_p)\)</span>可以得到它在世界空间中的坐标为</p>
<p></p><div class="math display">\[\mathbf{p}=(x_p,y_p)\equiv\mathbf{o}+x_p\mathbf{x}+y_p\mathbf{y}
\]</div><p></p><p>使用某个坐标系中的坐标<span class="math inline">\((u_p,v_p)\)</span>可以得到它在规范坐标系中的坐标为</p>
<p></p><div class="math display">\[\mathbf{p}=(u_p,v_p)\equiv\mathbf{e}+u_p\mathbf{u}+v_p\mathbf{v}
\]</div><p></p><p>因此,某个坐标系中的坐标<span class="math inline">\((u_p,v_p)\)</span>和它在规范坐标系中的坐标<span class="math inline">\((x_p,y_p)\)</span>的关系为</p>
<p></p><div class="math display">\[\begin{bmatrix} x_p \\ y_p \\ 1 \end{bmatrix} = \begin{bmatrix} x_u &amp; x_v &amp; x_e \\ y_u &amp; y_v &amp; y_e \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} u_p \\ v_p \\ 1 \end{bmatrix}
\]</div><p></p><p>让它变简洁点可以化简成</p>
<p></p><div class="math display">\[\mathbf{p}_{xy}=\begin{bmatrix} \mathbf{u} &amp; \mathbf{v} &amp; \mathbf{e} \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \mathbf{p}_{uv}
\]</div><p></p><p>我们称等式右侧的矩阵为<strong>帧到规范</strong>(<strong>Frame-To-Canonical</strong>)矩阵,它把在某个坐标系下的坐标转化为在规范坐标系下的坐标。从另一个方向变换,我们可以得到</p>
<p></p><div class="math display">\[\begin{bmatrix} u_p \\ v_p \\ 1 \end{bmatrix} = \begin{bmatrix} x_u &amp; y_u &amp; 0 \\ x_v &amp; y_v &amp; 0 \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; 0 &amp; -x_e \\ 0 &amp; 1 &amp; -y_e \\ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x_p \\ y_p \\1 \end{bmatrix}
\]</div><p></p><p>让它变简洁点可以化简成</p>
<p></p><div class="math display">\[\mathbf{p}_{uv}=\begin{bmatrix} \mathbf{u} &amp; \mathbf{v} &amp; \mathbf{e} \\ 0 &amp; 0 &amp; 1 \end{bmatrix}^{-1} \mathbf{p}_{xy}
\]</div><p></p><p>我们称等式右侧的矩阵为<strong>规范到帧</strong>(<strong>Canonical-To-Frame</strong>)矩阵,它把在规范坐标系下的坐标转化为在某个坐标系下的坐标。因此在三维中我们有</p>
<p></p><div class="math display">\[\begin{align*}
\begin{bmatrix} x_p \\ y_p \\ z_p \\ 1 \end{bmatrix}&amp;=\begin{bmatrix} 1 &amp; 0 &amp; 0 &amp; x_e \\ 0 &amp; 1 &amp; 0 &amp; y_e \\ 0 &amp; 0 &amp; 1 &amp; z_e \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x_u &amp; x_v &amp; x_w &amp; 0 \\ y_u &amp; y_v &amp; y_w &amp; 0 \\ z_u &amp; z_v &amp; z_w &amp; 0 \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} u_p \\ v_p \\ w_p \\1 \end{bmatrix} \\ \mathbf{p}_{xyz} &amp;= \begin{bmatrix} \mathbf{u} &amp; \mathbf{v} &amp; \mathbf{w} &amp; \mathbf{e} \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \mathbf{p}_{uvw}
\end{align*}
\]</div><p></p><p></p><div class="math display">\[\begin{align*}
\begin{bmatrix} u_p \\ v_p \\ w_p \\ 1 \end{bmatrix} &amp;= \begin{bmatrix} x_u &amp; y_u &amp; z_u &amp; 0 \\ x_v &amp; y_v &amp; z_v &amp; 0 \\ x_w &amp; y_w &amp; z_w &amp; 0 \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} 1 &amp; 0 &amp; 0 &amp; -x_e \\ 0 &amp; 1 &amp; 0 &amp; -y_e \\ 0 &amp; 0 &amp; 1 &amp; -z_e \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix} x_p \\ y_p \\ z_p \\ 1 \end{bmatrix} \\ \mathbf{p}_{uvw} &amp;= \begin{bmatrix} \mathbf{u} &amp; \mathbf{v} &amp; \mathbf{w} &amp; \mathbf{e} \\ 0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix}^{-1} \mathbf{p}_{xyz}
\end{align*}
\]</div><p></p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:TiredInkRaven,转载请注明原文链接:https://www.cnblogs.com/TiredInkRaven/p/18909254</p><br><br>
来源:https://www.cnblogs.com/TiredInkRaven/p/18909254
頁: [1]
查看完整版本: 《Fundamentals of Computer Graphics》第七章 矩阵变换