第 4 章 矩阵导论 (Introduction to Matrices)

      +

      核心结论

      • 矩阵的代数定义:r×c 数字网格;向量 = 1×n 行向量或 n×1 列向量;行向量是 1×n 矩阵的特殊情况。

      • 矩阵乘法:r×n 矩阵与 n×c 矩阵相乘得 r×c 矩阵;结果元素 = 左矩阵行与右矩阵列的 点积;不满足交换律,AB ≠ BA。

      • 行向量 vs 列向量:决定 v M(行向量前置)vs M v(列向量后置)的运算顺序;本书默认行向量,导致 v' = v M;用列向量的引擎(D3D、Unity)则 v' = M v,矩阵要预转置。

      • 矩阵的几何解释:方阵的 每一行 = 变换后基向量的坐标(行向量约定下);任何向量变换 = "用新基向量对原坐标做线性组合"。

      • 线性变换:保持直线与平行线、保持原点不动;可缩放但不弯曲;包含旋转 / 缩放 / 正交投影 / 反射 / 剪切;不含平移(平移需 4×4 齐次矩阵,第 6 章)。

      • 构造矩阵的工具:给出目标变换 → 看基向量映射到哪 → 把映射后的基向量写进矩阵行;这把"理解矩阵"与"构造矩阵"统一为同一工具。

      • 矩阵的更大图景:3D 图形只是线性代数的一角;解线性方程组、最小二乘拟合、约束物理等都用同一套矩阵工具。

      本章主旨

      本章把"基向量线性组合"代数化为矩阵乘法。理解两件事:(1) 矩阵的每一行(行向量约定)就是变换后的基向量——看懂矩阵就是看懂基向量去哪了;(2) 给定目标变换(如旋转、缩放、剪切)可逆向构造矩阵——把基向量的目标位置写进行。这两件事把"理解矩阵"和"构造矩阵"统一成同一把尺子。第 5 章用此工具导出旋转 / 缩放 / 投影 / 反射 / 剪切的具体矩阵,第 6 章用 4×4 齐次矩阵加入平移。

      一、核心概念

      本章围绕 6 个核心概念展开:从矩阵的代数基础(维度 / 转置 / 乘法)出发,澄清行 vs 列向量的约定,建立"矩阵行 = 变换后基向量"的几何解释,明确线性变换的边界(不含平移),最后给出构造矩阵的统一工具与线性代数的更广背景。

      概念 定义 + 重要性 实现提示

      矩阵的代数基础

      r×c 数字网格;下标记号 m[i][j](1-indexed 数学惯例 vs 0-indexed 编程惯例)。Iₙ 是乘法单位元。

      §4.1.1-§4.1.2;C++ 矩阵类常用命名成员(如 m11, m12, m21, m22)代替裸数组,避免索引错位。

      矩阵乘法

      r×n · n×c ⇒ r×c;元素 c[i][j] = Σₖ a[i][k] b[k][j] = 左矩阵行与右矩阵列的点积;不交换

      §4.1.6-§4.1.7;理解点积是矩阵乘法的代数核心。代码侧固定使用库内 Mat::operator*

      行向量 vs 列向量

      行向量:1×n 矩阵,v M;列向量:n×1 矩阵,M v;两者数学等价,但代码侧默认约定不同。本书默认行向量,D3D / Unity 默认列向量。

      §4.1.7-§4.1.8;跨引擎时矩阵要预转置(M_bookᵀ)。C++ 类建议用类型标签(RowVec / ColVec)区分。

      矩阵的几何解释

      方阵的 每一行(行向量约定)= 变换后基向量的坐标;变换 v' = v M 即"用新基向量对 v 的坐标做线性组合"。

      §4.2;2D 矩阵的"L 形"、3D 矩阵的"三脚架"是快速可视化工具。理解这一等式就能"看"任何矩阵。

      线性变换的边界

      方阵代表线性变换:保持直线、保持平行线、保持原点不动;可缩放但不弯曲;包含旋转 / 缩放 / 正交投影 / 反射 / 剪切;不含平移

      §4.2 引言;平移必须借助 4×4 齐次矩阵(第 6 章)。理解边界有助于判断"该用 4×4 还是 3×3 矩阵"。

      构造矩阵 = 给基向量定目标

      给定目标变换(旋转 / 缩放 / 剪切),看基向量映射到哪 → 把映射后坐标写进矩阵行;这把"读矩阵"和"写矩阵"统一为同一工具。

      §4.2 末段;第 5 章反复使用此方法构造旋转 / 缩放 / 投影 / 反射 / 剪切矩阵。

      二、详细笔记

      2.1 矩阵的代数基础 (Mathematical Definition)

      What:矩阵 = r×c 数字网格;标量是单个数,向量是 1D 数组,矩阵是 2D 数组(行 × 列)。

      Why:矩阵的代数规则(维度 / 转置 / 乘法)必须在几何理解之前建立;不熟悉代数规则会被 §4.2 几何解释卡住。

      How

      矩阵基本术语:

      • 维度:r 行 × c 列 = r×c 矩阵;3D 图形常用 2×2、3×3、4×4。

      • 下标记号m[i][j](1-indexed 数学;与 C++ 0-indexed 不同);读作 "m i j"。

      • 方阵:行数 = 列数;n×n 方阵;本书重点。

      • 对角元素m[i][i];其余 非对角

      • 对角矩阵:所有非对角元素为 0。

      • 单位矩阵 Iₙ:对角元素全 1、其余全 0 的 n×n 矩阵;矩阵乘法单位元(M I = I M = M)。

      索引错位的常见陷阱

      数学从 1 开始、C++ 从 0 开始。把矩阵存为 float m[3][3] 时,m[i][j] 在 0-indexed 下访问 m[i][j],但在 1-indexed 数学下访问的是 m[i+1][j+1]。建议矩阵类用命名成员(m11, m12, m21, m22)而不是裸数组,从源头消除歧义。

      When:所有线性代数场景;3D 图形主要是 3×3(旋转 / 缩放 / 剪切)和 4×4(含平移)。

      Example:\(\mathbf{M} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix}\) 是 3×2 矩阵;m21 = 3(第二行第一列 = 3)。

      2.2 矩阵乘法 (Matrix Multiplication)

      What:r×n 矩阵 A 与 n×c 矩阵 B 相乘得 r×c 矩阵 C;元素 c[i][j] = Σₖ a[i][k] b[k][j] = A 第 i 行与 B 第 j 列的 点积

      Why:矩阵乘法是线性变换组合的代数形式(先变换 1 再变换 2 = 总变换矩阵 M = M₂M₁);不理解乘法规则就读不懂"为什么父变换在右"。

      How

      定义(式 4-3 的 n 维一般化):

      \[c_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj} = (\text{A 第 i 行}) \cdot (\text{B 第 j 列})\]

      维度匹配规则:A 列数 = B 行数;不匹配则乘法 未定义

      关键性质:

      • 结合律A(BC) = (AB)C(前提是维度匹配)。

      • 不交换AB ≠ BA,甚至 BA 可能未定义。

      • 单位元AI = IA = A

      • 结合律与数乘k(AB) = (kA)B = A(kB)

      维度匹配的实用记法

      "内部维度相等"是矩阵乘法可执行的必要条件。A 是 m×n、B 是 n×p,则 AB 是 m×p;外部维度决定结果大小,内部维度"相消"。这与函数复合 f: A→B, g: B→Cg∘f 类型匹配是同构。

      When:变换组合(先 A 再 B 等于 B A,注意顺序);解线性方程组(Ax = b,左乘 A⁻¹);点积写成 a · b = aᵀ b(行 × 列)。

      Example:A = [[1,2],[3,4]]、B = [[2,0],[1,2]],则 AB = [[1·2+2·1, 1·0+2·2], [3·2+4·1, 3·0+4·2]] = [[4, 4], [10, 8]]。

      2.3 行向量 vs 列向量 (Row vs Column Vectors)

      What:向量有两种矩阵形式——1×n 行向量(横向)或 n×1 列向量(纵向);数学上等价,代码侧默认约定决定运算顺序。

      Why:把行向量约定下的矩阵搬到列向量引擎(D3D、Unity),结果是 镜像 / 反向 的变换——这是跨引擎复用代码最常见的错误。

      How

      约定差异:

      • 行向量约定(本书、OpenGL 早期):v' = v M;向量在左、矩阵在右;矩阵的 是变换后基向量。

      • 列向量约定(D3D、Unity、OpenGL 现代、GLSL):v' = M v;向量在右、矩阵在左;矩阵的 是变换后基向量。

      • 互转:列向量约定的矩阵 = 行向量约定的 转置;反之亦然。

      为什么选择行向量?本书作者的理由——向量写在公式左侧与自然语言("变换向量 v")的语序一致;学生更易记"先发生的事写在右边"。

      跨引擎转置速记

      把 OpenGL 行向量矩阵 M_row 喂给 D3D 列向量代码,必须 M_col = M_rowᵀ(包括 4×4 齐次矩阵的平移行 / 列)。否则会出现"模型位置正确但朝向镜像"或"整体绕原点对称翻转"等诡异 bug。

      When:写跨引擎代码时第一件事是确认约定;选引擎的数学库时也优先看其约定(DirectXMath = 列向量,GLM 默认列向量但提供 row-major 标志)。

      Example:旋转矩阵 R_row = (行向量约定把 +x 转到 +y);列向量约定的同一旋转 R_col = R_rowᵀ =

      2.4 矩阵的几何解释 (Geometric Interpretation)

      What:方阵的 每一行(行向量约定)= 变换后基向量的坐标;变换 v' = v M 即"用新基向量对 v 的坐标做线性组合"。

      Why:这是 3D 图形的关键洞察——任何矩阵都可视化为"基向量去哪了";理解这一条规则,看矩阵就像看动画。

      How

      把基向量 i = [1,0,0]j = [0,1,0]k = [0,0,1] 右乘矩阵 M:

      \[\mathbf{i} \mathbf{M} = [m_{11}, m_{12}, m_{13}] \quad \mathbf{j} \mathbf{M} = [m_{21}, m_{22}, m_{23}] \quad \mathbf{k} \mathbf{M} = [m_{31}, m_{32}, m_{33}]\]

      因此"矩阵 M 的第 i 行"就是基向量变换后的位置。

      可视化:

      • 2D:行向量画出来形成 L 形(两个基向量);平行四边形补全得"skew box"(倾斜盒子)。

      • 3D:行向量画出来形成 三脚架(三个基向量);可加参考物体(茶壶、立方体)增强直观。

      为什么"行"是基向量(行向量约定下)

      因为 \(\mathbf{v}' = \mathbf{v} \mathbf{M} = (v_x \mathbf{i} + v_y \mathbf{j} + v_z \mathbf{k}) \mathbf{M} = v_x (\mathbf{i}\mathbf{M}) + v_y (\mathbf{j}\mathbf{M}) + v_z (\mathbf{k}\mathbf{M})\),即变换后的 v'变换后基向量的线性组合。列向量约定下推导对称,但"列是基向量"。

      When:调试时把矩阵按行画出来即可知道"基向量去哪了";设计变换时逆向思考"我要让基向量去哪"再写矩阵。

      ExampleM = [[2, 1], [-1, 2]](2D)。第 1 行 [2, 1] = +x 基向量映射到 (2, 1);第 2 行 [-1, 2] = +y 基向量映射到 (-1, 2)。整体看:绕原点逆时针约 26.5° + 缩放。

      2.5 线性变换的边界 (Linear Transformation Boundaries)

      What:方阵代表 线性变换——保持直线、保持平行线、保持原点不动;可缩放但不弯曲。

      Why:理解边界决定何时用 3×3、何时升级到 4×4;含平移的变换必须用 4×4 齐次矩阵。

      How

      线性变换的核心性质(§4.2 + §5.7.1):

      • 保直:直线变换后仍是直线。

      • 保平行:平行线变换后仍平行(相交线可能相交于新点)。

      • 保原点:原点永远不动。

      • 可缩放但不弯曲:长度、角度、面积、体积可能改变;曲线不会变成曲线外的形状。

      • 包含的变换类型:旋转、缩放、正交投影、反射、剪切。

      线性变换 = 矩阵乘法

      \(\mathbf{f}(\mathbf{v} + \mathbf{w}) = \mathbf{f}(\mathbf{v}) + \mathbf{f}(\mathbf{w})\) 且 \(\mathbf{f}(k\mathbf{v}) = k\mathbf{f}(\mathbf{v})\)——这恰好是矩阵乘法的代数性质。因此所有线性变换都能用矩阵表达,所有矩阵都对应线性变换。

      When:3×3 矩阵足够时的场景(仅旋转 / 缩放 / 剪切 / 投影 / 反射,不含平移);含平移 → 4×4 齐次矩阵(第 6 章)。

      Example:绕 z 轴旋转 θ 是线性变换——用 3×3 旋转矩阵即可。绕任意点旋转 = 先平移到原点(线性) + 旋转(线性) + 平移回去(非线性,但用 4×4 整体仍是仿射变换)——必须升级到 4×4。

      2.6 构造矩阵 = 给基向量定目标 (Constructing Matrices from Transformations)

      What:给定目标变换(旋转 / 缩放 / 剪切),看基向量映射到哪 → 把映射后的基向量写进矩阵行;这把"读矩阵"和"写矩阵"统一为同一工具。

      Why:5 章所有具体变换矩阵的推导都用此方法;理解后能推导"为什么旋转矩阵长这样",而不只是死记公式。

      How

      构造步骤:

      1. 明确基向量的目标:在目标变换下,+x 基向量去哪?+y 基向量去哪?+z 基向量去哪?

      2. 写进矩阵行:第 i 行 = +i 基向量变换后的坐标。

      3. (可选)验证:把 i, j, k 右乘矩阵,看是否回到目标位置。

      同一工具的正向与逆向
      • 正向(读矩阵):M → 看每行 → 知基向量去哪了 → 知变换形状(L / 三脚架 / skew box)。

      • 逆向(写矩阵):变换目标 → 算基向量去哪 → 写进每行 → 得 M

      正逆两向是同一把尺子的两端。第 5 章反复使用此方法。

      When:第 5 章构造旋转 / 缩放 / 投影 / 反射 / 剪切矩阵;自定义变换(如错切、倾斜投影);shader 中的内置矩阵(如投影矩阵)验证。

      Example:绕 z 轴逆时针旋转 90°。+x+y(矩阵第 1 行 = [0, 1, 0]);+y-x(矩阵第 2 行 = [-1, 0, 0]);+z 不动(矩阵第 3 行 = [0, 0, 1])。得 R_z(90°) = [[0, -1, 0], [1, 0, 0], [0, 0, 1]]ᵀ…… 等等,行向量约定下实际写为 R_z(90°) = [[0, 1, 0], [-1, 0, 0], [0, 0, 1]]

      三、关键图表

      视觉图表

      图 4-1
      Figure 1. 图 4-1:2D 变换矩阵的行向量(L 形)
      图 4-2
      Figure 2. 图 4-2:2D 平行四边形(skew box)
      图 4-3
      Figure 3. 图 4-3:把物体画进盒子以可视化变换
      图 4-4
      Figure 4. 图 4-4:变换前的茶壶、单位立方体、基向量
      图 4-5
      Figure 5. 图 4-5:变换后(绕 z 旋转 45° + 缩放)

      非可视化条目

      非可视化条目(表 / 算法)
      编号 内容摘要

      式 4-1, 4-2

      矩阵转置的两个示例:4×3 → 3×4、3×3 转置自身不变。

      式 4-3

      2×2 矩阵乘法完整展开式。

      式 4-4 至 4-7

      3×3 与 4×4 矩阵乘法展开;行向量约定 v M 与列向量约定 M v 的对比。

      式 4-8

      行向量约定下"v M = vx (iM) + vy (jM) + vz (kM)"——行向量右乘矩阵 = 变换后基向量的线性组合。

      核心公式对照表

      核心公式对照表
      式号 公式

      矩阵乘法定义

      \(c_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj}\)

      行向量约定

      \(\mathbf{v}' = \mathbf{v} \mathbf{M}\)

      列向量约定

      \(\mathbf{v}' = \mathbf{M} \mathbf{v}\)

      互转关系

      \(\mathbf{M}_{\text{col}} = \mathbf{M}_{\text{row}}^T\)

      基向量变换

      \(\mathbf{i}\mathbf{M} = [m_{11}, m_{12}, m_{13}\)]

      \(\mathbf{j}\mathbf{M} = [m_{21}, m_{22}, m_{23}\)]

      \(\mathbf{k}\mathbf{M} = [m_{31}, m_{32}, m_{33}\)]

      线性组合解释

      \(\mathbf{v}' = v_x (\mathbf{i}\mathbf{M}) + v_y (\mathbf{j}\mathbf{M}) + v_z (\mathbf{k}\mathbf{M})\)

      四、思维导图

      mindmap
        root((第 4 章 矩阵导论))
          代数基础
            维度与下标
            方阵与单位阵
            转置数乘
          矩阵乘法
            维度匹配
            行与列点积
            不交换
          向量约定
            行向量本书
            列向量D3D
            互转转置
          几何解释
            行是变换后基向量
            2D的L形
            3D的三脚架
          线性变换
            保直保平行
            保原点
            不含平移
          构造矩阵
            基向量定目标
            写进行
            正逆统一

      五、重点与易错点

      1. 索引从 1 开始:数学用 m[i][j](1-indexed),C++ 用 m[i-1][j-1](0-indexed);建议矩阵类用命名成员(如 m11, m12)消除歧义。

      2. 矩阵乘法不交换AB ≠ BA,先 A 再 B 与先 B 再 A 一般得到不同结果(甚至未定义);变换组合顺序永远是"先发生的写在右边"(行向量约定)。

      3. 维度匹配是矩阵乘法的硬约束A r×n · B n×c ⇒ r×c;不匹配即 undefined;与函数复合 f: A→B, g: B→C 类型同构。

      4. 行向量 vs 列向量的跨引擎差异:本书用 v' = v M;D3D / Unity / GLSL 用 v' = M v;矩阵互为转置;混用会导致模型镜像 / 翻转等诡异 bug。

      5. 矩阵的"行"是变换后基向量(行向量约定):把 +x 映射到哪写第一行,+y 映射到哪写第二行;2D 看 L 形、3D 看三脚架。

      6. 构造矩阵的正向与逆向统一:给定变换 → 看基向量目标 → 写进行;第 5 章所有具体矩阵都由此方法推导。

      7. 3×3 不含平移:含平移的变换(如"绕任意点旋转")必须升级到 4×4 齐次矩阵(第 6 章);混用会导致原点漂移。

      8. 零向量右乘任何矩阵 = 零向量:linear transformation 保原点;这条性质可以用来快速检查矩阵是否合法。

      9. 矩阵单位元 I 与数的 1 同构M I = I M = M;把 I 误写为全 1 会把变换搞成"全部坐标 +=1"式平移。

      10. 跨章衔接:第 5 章用本章"行 = 基向量"工具构造旋转 / 缩放 / 投影 / 反射 / 剪切矩阵;第 6 章升级到 4×4 齐次矩阵加入平移;第 8 章把旋转矩阵推广到欧拉角 / 四元数;第 10 章把"变换链"具体为模型 → 世界 → 相机 → 投影链。