几何学——矩阵基础知识汇总

发布于 2023-05-05 10:02:38

矩阵介绍

这是一篇一看到底的文章,主要是全面剖析矩阵。众所周知,矩阵是一个由数值排列成的矩形阵列。矩阵在CG图形流水线中起着重要作用,你会在 3D 应用程序的代码中经常看到它们的使用。矩阵没有什么复杂的;如果你害怕它们,那可能是因为你还没有完全理解它们的工作机理。所以让我们来一起解决它,这篇文章我将会把所有关于矩阵的知识罗列出来。希望后续同学有关于矩阵的知识都可以在下面留言,不断丰富文章。

矩阵.jpg

矩阵是什么

为了更易于理解矩阵的概念,我们将从实际的矩阵示例开始,而不是使用抽象的数学定义。通过观察具体的例子,我们可以更容易地将这些概念扩展到其通用/数学形式。在计算机图形学中,我们通常使用二维数组来表示矩阵。这些数组使用标准符号 mxn 进行定义,其中 m 和 n 是表示数组大小的两个数字。在矩阵中,m 表示矩阵的行数,而 n 则表示矩阵的列数。行代表着二维数组中水平的数字行,而列则代表垂直的数字列。下面是一个 [3x5] 矩阵的示例:

$$ \begin{bmatrix} 11&3&72&9&90\\ 32&3&20&8&3\\ 92&1&10&0&1 \end{bmatrix} $$

进而我们可以生成下面通用的公式

$$ \begin{bmatrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n} \\ a_{2,1} & a_{2,2} & \cdots & a_{2,n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m,1} & a_{m,2} & \cdots & a_{m,n} \end{bmatrix} $$

上述代码将会生成一个 m×n 的矩阵,其中每个元素都用 Ai,j表示。i指的是行号和j指的是列号。

矩阵秩是矩阵理论中的一个重要概念,它描述了矩阵所包含的线性无关向量的个数。

矩阵秩的通俗易懂定义是:一个矩阵的秩就是它所包含的线性无关列向量(或行向量)的最大数量。可以简单地理解为一个矩阵中不重复的列向量(或行向量)的数量。

举例来说,考虑以下3x3 矩阵:

$$ A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} $$

我们可以观察到第一列是(1,4,7),第二列是(2,5,8,第三列是 (3,6,9)。我们可以看出,这些列向量并不是线性无关的。为了证明这一点,我们可以使用矩阵的初等变换将矩阵变换为其行简化阶梯形式:

$$ \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} \to \begin{bmatrix} 1 & 2 & 3 \\ 0 & -3 & -6 \\ 0 & -6 & -12 \end{bmatrix} \to \begin{bmatrix} 1 & 2 & 3 \\ 0 & -3 & -6 \\ 0 & 0 & 0 \end{bmatrix} $$

从这里可以看出,矩阵的第一列包含了基本变量,而其他两列不包含任何基本变量,因此 $A$ 的秩是 $1$。

换句话说,我们可以将 $A$ 看作是一组线性相关的向量 (1,4,7)(2,5,8)(3,6,9)构成的集合。因此,A 的秩为 2

方阵

但是通常通常,在 CG 中,我们会对·3x34x4 矩阵感兴趣(也就是我们数学中常说的方阵),我们将在下一章中告诉您它们是什么以及如何使用它们。这些矩阵通常称为方阵(如果 m = n,则矩阵 [mxn] 是方阵)。这是一种简化,因为 m 和 n 可以取任何值并且不必相等。例如,您可以创建 3x1 矩阵、6x6 矩阵或 4x2 矩阵。它们都是有效的矩阵。但正如我们所说,我们将主要在 CG 中使用 3x3 4x4 矩阵。

(1)3x3 矩阵

$$ \begin{bmatrix} 7&4&3\\ 2&0&3\\ 3&9&1\\ \end{bmatrix} $$

(2)4x4 矩阵

$$ \begin{bmatrix} 7&1&4&3\\ 2&0&0&3\\ 3&1&9&1\\ 6&6&5&4\\ \end{bmatrix} $$

下面我们看在着色器(类C)中实现矩阵:

myMatrix3x3 = mat3(1.0, 2.0, 3.0,
                   4.0, 5.0, 6.0,
                   7.0, 8.0, 9.0);
myMatrix4x4 = mat4(1.0, 0.0, 0.0, 0.0,
                   0.0, 1.0, 0.0, 0.0,
                   0.0, 0.0, 1.0, 0.0,
                   0.0, 0.0, 0.0, 1.0);

冰哥说:在C++中表示方法和shader中是类似的,就是API方式不一样。但是在javascript中不能直接表示矩阵,而是通过数组形式表示。通过API截取不同长度的数组值,去划分矩阵的行和列。

对角矩阵

顾名思义,在矩阵正对角线不为0,其余位置都为0的方阵就是对角矩阵。可以参考下面的矩阵例子:

$$ \begin{bmatrix} 7&0&0\\ 0&1&0\\ 0&0&1\\ \end{bmatrix} $$

shader中实现对角矩阵如下代码所示:

mat4 diagonalMatrix = mat4(2.0, 0.0, 0.0, 0.0,
                           0.0, 3.0, 0.0, 0.0,
                           0.0, 0.0, 4.0, 0.0,
                           0.0, 0.0, 0.0, 1.0);

单位矩阵

单位矩阵是一种特殊的对角矩阵。对角元素为 1,其他元素为0。请看下面的矩阵例子:

$$ \begin{bmatrix} 1&0&0\\ 0&1&0\\ 0&0&1\\ \end{bmatrix} $$

shader中一般这样声明单位矩阵:

mat3 Matrix = mat3(1.0);

冰哥说:单位矩阵非常特殊,用任意一个矩阵乘以单位矩阵,都将得到原矩阵。我们回忆大学的线性代数,我们一般用单位矩阵去推导公式,两个互为逆矩阵相乘得到单位矩阵,反之我们可以将单位矩阵分解为两个逆矩阵去推导其他公式。

奇异矩阵

奇异矩阵是线性代数的概念,就是该矩阵的秩不是满秩。

首先,看这个矩阵是不是方阵(即行数和列数相等的矩阵,若行数和列数不相等,那就谈不上奇异矩阵和非奇异矩阵)。如是方阵,再看此矩阵的行列式|A|是否等于0,若等于0,称矩阵A为奇异矩阵;若不等于0,称矩阵A为非奇异矩阵。

伴随矩阵

伴随矩阵(Adjoint matrix)也称作伴随阵或伴随矩阵,是方阵的一个重要概念。设 A 是 n 阶方阵,A 的伴随矩阵记为 adj(A),其定义如下:

  • 将 A 矩阵的每个元素 ai 替换为它的代数余子式 Aij,即去掉第 i 行和第 j 列后剩下元素的行列式 Dij 的符号因子。
  • 将新生成的矩阵转置,得到的矩阵即为 A 的伴随矩阵。

我们来看看下面这个例子:

假设有矩阵

$$ A = \begin{pmatrix} 2 & 3 \\ 5 & 4 \end{pmatrix} $$

首先,我们需要计算A 的行列式,就是

$$ |A| = 2 \times 4 - 3 \times 5 = -7 $$

接下来,我们需要计算 A 的代数余子式,也就是每个元素的代数余子式。对于这个矩阵,代数余子式的计算方法是交替取符号的次序行列式,而每个次序行列式就是去掉对应行和列后的矩阵的行列式。

因此,我们可以得到:

$$ A_{11} = (-1)^{1+1} \begin{vmatrix} 4 \end{vmatrix} = 4 \\ A_{12} = (-1)^{1+2} \begin{vmatrix} 5 \end{vmatrix} = -5 \\ A_{21} = (-1)^{2+1} \begin{vmatrix} 3 \end{vmatrix} = -3 \\ A_{22} = (-1)^{2+2} \begin{vmatrix} 2 \end{vmatrix} = 2 $$

然后,我们将这些代数余子式放入矩阵中,得到矩阵 A 的伴随矩阵:

$$ adj(A) = \begin{pmatrix} A_{11} & A_{21} \\ A_{12} & A_{22} \end{pmatrix}^T = \begin{pmatrix} 4 & -3 \\ -5 & 2 \end{pmatrix} $$

逆矩阵

逆矩阵是指对于一个给定的方阵A,如果存在一个方阵B使得A乘以B等于B乘以A等于单位矩阵I,则称方阵B为A的逆矩阵,记作

$$ A^{-1} $$

其中,我们上面讲到单位矩阵指的是对角线上所有元素都为1,其余元素都为0的方阵。

冰哥说:要求一个矩阵A的逆矩阵,需要保证以下两个条件都满足:

  1. 矩阵A必须是一个方阵。只有方阵才具有逆矩阵。
  2. 矩阵A必须是可逆的。即行列式不为0。

如果以上两个条件都满足,则可以使用伴随矩阵求解逆矩阵。具体步骤如下:

  1. 先计算出矩阵A的行列式|A|,如果|A|=0,则矩阵A不可逆。
  2. 计算矩阵A的伴随矩阵adj(A),其中adj(A)的每个元素等于A的代数余子式所组成的矩阵的转置矩阵。
  3. 计算逆矩阵A的值为

    $$ A^{-1}=\frac{1}{|A|}adj(A) $$

需要注意的是,当矩阵A是奇异矩阵时,即行列式为0时,该矩阵没有逆矩阵。此外,逆矩阵不一定存在,但如果存在,则是唯一的。

我们来看看shader中或者其他矩阵转换库中如何实现逆矩阵转换,具体转换思路和上面过程是类同的,我将在代码层面注明关键部分:

mat3 inverse(mat3 m) {
//将3X3矩阵中各个元素的值分解开来,方便后续使用
    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];

//求伴随矩阵
    float b01 = a22 * a11 - a12 * a21;
    float b11 = -a22 * a10 + a12 * a20;
    float b21 = a21 * a10 - a11 * a20;
//求行列式
    float det = a00 * b01 + a01 * b11 + a02 * b21;
//求逆矩阵 伴随矩阵中各个元素分别除以行列式的值
    return mat3(
        b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
        b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
        b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)
    ) / det;
}

冰哥说:我们以三阶矩阵为例子,因为常用的就三阶矩阵或者四阶矩阵。

转置

考虑一个RXC矩阵 M。M 的转置记作MT,是一个RXC矩阵,它的列由 M 的行组成。可以从另一方面理解,MT=M,即沿着矩阵的对角线翻折。如下面这个例子

$$ \left[\begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{matrix}\right]^{T} = \left[\begin{matrix} 1 & 4 & 7 \\ 2 & 5 & 8 \\ 3 & 6 & 9 \\ \end{matrix}\right] $$

冰哥说:对于任意矩阵 M,(MT)T=M 。从另一方面来说,将一个矩阵转置后,再转置一次,便会得到原矩阵。这条法则对向量也适用,对于任意对角矩阵 D,都有 DT =D,包括单位矩阵I也如此。

我们来看看shader中或者其他矩阵转换库中如何实现矩阵转置,具体转换思路和上面过程是类同的,只不过用代码实现了一遍,我将在代码层面注明关键部分:

mat4 transpose(mat4 m) {
   return mat4(m[0][0], m[1][0], m[2][0], m[3][0],
               m[0][1], m[1][1], m[2][1], m[3][1],
               m[0][2], m[1][2], m[2][2], m[3][2],
               m[0][3], m[1][3], m[2][3], m[3][3]);
}

总结

我们基本将矩阵里的常见概念做了总结和梳理,后续我们继续讨论关于矩阵的高级用法!

2 条评论

发布
问题