本篇位置:模块一 · 第 2 篇 | 前置:坐标系与向量 | 预计阅读:40 分钟
上一篇讲的是坐标和向量。这一篇先把视线收窄到二维平面上的线性变换:缩放、翻转、旋转,以及把它们组合起来的矩阵乘法。
先暂时不看平移矩阵。平移不能由 2×2 矩阵完成,必须等下一篇引入齐次坐标后才能和其他变换统一写进一个矩阵。
所以本篇的主角是一张 2×2 矩阵:它如何改变坐标轴、如何改变面积和绕序,以及为什么组合时顺序不能交换。涉及平移的齐次坐标留到下一篇。
- 拿到一个 2×2 矩阵,光看它的两列就能说出它把空间怎么样了。
- 手写缩放、翻转、旋转矩阵,并说清 sin、cos 为什么会出现在旋转矩阵里。
- 说清"把两个变换接起来"为什么就是"把两个矩阵乘起来",以及为什么顺序不能换。
- 用行列式的符号判断一个变换有没有把图形翻面,用它的值判断能不能求逆。
- 解释为什么平移不能塞进 2×2,以及它为什么需要下一篇的齐次坐标。
本篇的坐标约定:原点在左上角,+X 向右,+Y 向下——就是 Android 屏幕坐标的约定。这和数学课本上 +Y 向上的画法是上下颠倒的,本篇所有的图都按屏幕坐标画。这个差别在第 3 节讲旋转时会产生一个具体后果,到时候会点明。
一个 2×2 矩阵乘一个二维向量,按定义展开就是四次乘法、两次加法:
[acbd][xy]=[ax+bycx+dy]
念法是"横着取矩阵的一行,竖着取向量,对应位置相乘再相加"。第一行 [ab] 配上 [xy] 得到 ax+by,这是结果的第一个分量;第二行同理。
拿具体数字走一遍。取 M=[2011],点 (3,4):
[2011][34]=[2×3+1×40×3+1×4]=[104]
就这么多。矩阵乘向量没有任何玄机,它就是一组固定的加权求和。 难的从来不是算,是知道这组数字在几何上意味着什么——这是下一节的事。
先记一个后面会反复用到的观察。把原点 (0,0) 代进去:
[acbd][00]=[a×0+b×0c×0+d×0]=[00]
不管 a,b,c,d 填什么,原点乘完还是原点。 也就是说,2×2 矩阵能做的事情里,永远不包括"把整个东西挪个位置"。这正是下一篇齐次坐标要解决的问题。
上一节说"难的是知道数字在几何上意味着什么"。
把 x 轴方向的单位向量 i=(1,0) 代进去:
[acbd][10]=[a×1+b×0c×1+d×0]=[ac]
结果 (a,c) 就是矩阵的第一列。再把 y 轴方向的单位向量 j=(0,1) 代进去,同样地会得到 (b,d),也就是矩阵的第二列。
于是有了这条本篇最值钱的结论:
矩阵的第一列,是 x 轴被搬到了哪里;第二列,是 y 轴被搬到了哪里。

图:左边是变换前,橙色箭头是 i=(1,0),蓝色箭头是 j=(0,1)。右边是被 M=[2011] 作用之后:橙色箭头落在 (2,0),正是矩阵第一列;蓝色箭头落在 (1,1),正是第二列。注意 +Y 向下,所以 j 是朝下画的。
为什么这条结论管用?因为任何一个点 (x,y) 都可以写成 x⋅i+y⋅j,而矩阵乘法保持这种"按比例相加"的结构不变——所以只要知道 i 和 j 去了哪,整个平面去了哪就定了。
以后再看到一个陌生的矩阵,第一件事就是把它竖着切成两列,看这两列指向哪。 这比试图心算它的效果快得多,也可靠得多。
有了"看列"这个工具,三种基本变换可以直接从几何要求反推出来。
缩放。 想让 x 方向拉 sx 倍、y 方向拉 sy 倍,那就是要 i 落到 (sx,0)、j 落到 (0,sy)。把这两个当成列写下来:
S=[sx00sy]
翻转是缩放的特例。 水平翻转就是让 x 变号、y 不动,也就是 sx=−1、sy=1:
H=[−1001]
这就是水平镜像在线性代数里的写法:第一列把 x 方向反过来,第二列保持 y 方向不变。
旋转要用到三角函数。 想把整个平面转 θ 角,先只问一个问题:i=(1,0) 转到哪去了?
i 的长度是 1,转动之后长度还是 1,所以它落在单位圆上。而单位圆上转过 θ 角那一点的坐标,正是 cosθ 和 sinθ——这就是 sin、cos 的定义本身,不是什么需要额外记忆的公式。所以 i 落到 (cosθ,sinθ)。
j 比 i 超前 90°,转动之后仍然超前 90°,坐标是 (−sinθ,cosθ)。两列写下来:
R(θ)=[cosθsinθ−sinθcosθ]
这就是旋转矩阵。它不是背下来的,是从"i 和 j 转到哪"两句话推出来的——忘了随时可以再推一遍。

图:用字母 F 当被变换的对象,因为它既不左右对称也不上下对称,一眼就能看出转了多少、有没有被镜像。淡灰色是原来的位置。
一个必须点明的后果。 上面那个 R(θ) 在数学课本里(+Y 向上)是逆时针转 θ 角。但在屏幕坐标里 +Y 是向下的,同一个矩阵看起来就变成了顺时针——图里"旋转 30°"那一格就是顺时针歪的。
矩阵没变,变的是你看它的坐标系。这类"公式是对的但方向反了"的困惑,几乎全部来自 Y 轴朝向,遇到时先检查这一点。
现在把两个变换接起来:先用 B 变一次,再用 A 变一次。写出来是
A(Bv)
矩阵乘法有个性质叫结合律,它允许你把括号挪个地方:
A(Bv)=(AB)v
这一步是矩阵乘法的全部意义所在:AB 这个乘出来的新矩阵,效果等于"先 B 后 A"这一整套连招。于是 n 个变换可以提前乘成一个矩阵,运行时每个顶点只做一次乘法——图形管线里一切"预先合并变换"的做法,根都在这里。
代价是必须记住读法:AB 作用在向量上时,靠近向量的那个先生效。 也就是从右往左读。
而顺序是不能随便换的,因为矩阵乘法不满足交换律:一般来说 AB=BA。这不是什么抽象的数学洁癖,用具体数字五秒就能验证。
取 H=[−1001](水平翻转),R=[01−10](转 90°,把 θ=90° 代进上一节的公式即得,因为 cos90°=0、sin90°=1)。
先算 RH(先翻转,后旋转):
RH=[01−10][−1001]=[0−1−10]
再算 HR(先旋转,后翻转):
HR=[−1001][01−10]=[0110]
两个结果差了一个负号,也就是差了一次 180° 旋转。

图:上排是"先翻转再旋转",下排是"先旋转再翻转"。同样两个动作,落点差了半圈。
2×2 矩阵默认绕原点变换。要绕别的中心 c 变换,不需要马上引入更高维的矩阵,只要把步骤写清楚:
- 从点 p 减去中心 c,把中心临时当成原点;
- 用 2×2 矩阵 A 变换这个差向量;
- 把中心加回来。
公式是
p′=c+A(p−c)
取一个宽 w、高 h 的矩形,中心是 c=(w/2,h/2)。水平镜像的线性部分是
AH=[−1001]
代入公式,得到
(x′,y′)=(w−x, y)
这解释了为什么镜像之后仍然留在原矩形里:先绕原点翻转,再把中心补回来。
绕原点的水平、垂直镜像分别是
H=[−1001],V=[100−1]
把它们相乘:
HV=[−100−1]
这正是 θ=180° 的旋转矩阵。若变换绕矩形中心进行,中心补回的结果就是
(x,y)⟶(w−x, h−y)
拿一部 1080×1920 的手机验算,点 (100,200) 会到
(1080−100, 1920−200)=(980,1720)
它和原点的中点是 (540,960),正好是矩形中心。

图:先水平翻转,再垂直翻转,结果与绕中心转 180° 完全一致。
行列式(determinant)是从矩阵算出来的一个数。2×2 的算法是主对角线乘积减去副对角线乘积:
det[acbd]=ad−bc
它有三层几何含义。
第一层:绝对值 = 面积被放大了多少倍。 单位正方形经过变换后变成平行四边形,面积就是 ∣det∣。
第二层:符号 = 有没有被翻面。 正号表示绕序保持不变,负号表示绕序反了,也就是发生了镜像。水平镜像的行列式是 −1:面积不变,但正反面交换。
第三层:行列式为 0 就不能求逆。 这意味着整个平面被压扁成一条线,面积归零,信息已经丢失。

任何纯旋转矩阵的行列式都是 1:
detR(θ)=cos2θ+sin2θ=1
面积不变、不翻面,符合"转一下不会改变图形大小或正反"的直觉。
矩阵 A 把点 p 变到 p′=Ap。逆变换做的事就是沿原路还原:
p=A−1p′,A−1A=I
这里的 I 叫单位矩阵(identity matrix):
I=[1001]
它乘任何向量都不改变向量,Ip=p;乘任何同阶矩阵也不改变矩阵,IA=AI=A。因此它在矩阵乘法里的作用,就像数字乘法里的 1。几何上,I 表示“什么变换也不做”。于是
A−1(Ap)=(A−1A)p=Ip=p
这完整地表达了“先做 A,再做 A−1,点回到原处”。所以 A−1A=I 不是说结果等于数字 1,而是说两个变换合起来等于单位变换。
用第 2 节的"看列"方法理解更直观:A 的两列是变换后的两根坐标轴,A−1 会把这两根轴送回 (1,0) 和 (0,1)。它不是另一种随意的变换,而是 A 的撤销操作。
三个基本例子:
- 放大 2 倍的逆,是缩小到 1/2;
- 旋转 30° 的逆,是旋转 −30°;
- 镜像再做一次相同镜像会回到原状,所以镜像矩阵的逆就是它自己。
只要 detA=0,2×2 矩阵就有逆:
A−1=ad−bc1[d−c−ba]
若 detA=0,某个方向已经被压扁,许多不同的点会落到同一个位置,当然无法从结果反推出原点。
先做 B、再做 A,组合是 AB。撤销时必须先撤销最后做的 A,再撤销 B:
(AB)−1=B−1A−1
这就像先穿袜子再穿鞋,脱的时候一定先脱鞋。顺序倒转不是公式游戏,而是"撤销操作"的必然结果。
转置(transpose)只是把矩阵的行和列互换,记作 AT:
A=[acbd],AT=[abcd]
如果把 A 的两列记成 u、v,那么
ATx=[u⋅xv⋅x]
也就是说,转置会用原矩阵的两列分别和 x 做点积。转置本身通常不是撤销操作;它只是重新组织行列,并把"列向量参与线性组合"换成"逐列做点积"的视角。
如果 A 的两列互相垂直,而且长度都是 1,那么它们构成一组标准正交基。此时用两列做点积,正好是在求一个点沿这两根轴的坐标,也就恰好撤销了原来的变换:
ATA=I⟹A−1=AT
满足这个条件的矩阵叫正交矩阵。旋转和镜像都属于这一类,它们只改变方向,不拉伸空间。
以 90° 旋转为例:
R=[01−10],RT=[0−110]=R−1
但缩放矩阵立刻说明两者通常不相等:
S=[2003],ST=S,S−1=[1/2001/3]
所以要记住的是:逆矩阵负责撤销;转置负责交换行列。只有列向量构成标准正交基时,转置才碰巧就是逆。
1. 一个宽 1080、高 1920 的矩形绕中心做垂直镜像,点 (100, 200) 会变成什么?
(100, 1720)。
只动 y:y′=h−y=1920−200=1720,x 保持 100 不变。
2. 旋转 90° 的矩阵是 [[0, −1], [1, 0]],它的行列式是多少?说明它有没有翻面?
det=0×0−(−1)×1=1。
正号,说明没翻面;值为 1,说明面积不变。这符合"旋转不改变图形的大小和正反"的直觉。事实上任何 R(θ) 的行列式都是 1(第 7 节验证过)。
3. 不查上文,从"i 转到哪、j 转到哪"重新推一遍旋转矩阵。
i=(1,0) 长度为 1,转 θ 后落在单位圆上角度 θ 的位置,坐标就是 (cosθ,sinθ)——这是 sin/cos 的定义。
j=(0,1) 比 i 超前 90°,转完仍超前 90°,落在 (−sinθ,cosθ)。
两个结果按列摆好:R(θ)=[cosθsinθ−sinθcosθ]。
4. 一个变换之后的坐标全是 NaN,从本篇内容出发你会先查什么?
先查行列式是不是 0。
求逆公式要除以行列式;如果行列式为 0,结果会出现 inf,之后所有依赖它的坐标都会变成 NaN。
几何上的解释是:det=0 表示这个变换把整个平面压扁成了一条线,面积归零,信息已经丢失,本来就无法还原。
5. 先做 $B$ 再做 $A$,合成矩阵应该写成 $AB$ 还是 $BA$?
应该写成 AB。
因为 A(Bv)=(AB)v,靠近向量的 B 先作用。
6. 从几何上说,$A^{-1}$ 对 $A$ 的两列做了什么?
A 的两列是被变换后的两根坐标轴。A−1 把它们分别送回 (1,0) 和 (0,1),因此会把整个被 A 改变的空间还原。
7. 对缩放矩阵 $S=\mathrm{diag}(2,3)$,$S^{\mathsf T}$ 和 $S^{-1}$ 分别是什么?为什么不相等?
ST=[2003],S−1=[1/2001/3]
转置只交换行列,所以对角矩阵转置后不变;逆矩阵要撤销缩放,所以缩放倍数必须取倒数。S 的列长度不是 1,它不是正交矩阵,因此转置不等于逆。
| 概念 | 一句话 | 数学写法 |
|---|
| 矩阵乘向量 | 一组固定的加权求和,没有玄机 | Av 里的两行加权求和 |
| 矩阵的列 | 第一列 =x 轴去了哪,第二列 = y 轴去了哪 | M=[i′ j′] |
| 缩放 / 翻转 | 对角线上填倍数;填−1 就是镜像 | diag(−1,1) |
| 旋转 | 从"i、j 转到哪"推出来,不用背 | R(90°) 就是那四个数 |
| 变换组合 | 接起来 = 矩阵相乘;靠近向量的先生效 | A(Bv)=(AB)v |
| 交换律 | 不成立,AB=BA,顺序写反是对错问题 | AB=BA |
| 绕非原点变换 | 先减中心 → 变换 → 加回中心 | p′=c+A(p−c) |
| 行列式 | 绝对值 = 面积倍数,符号 = 有没有翻面,为 0 = 不可逆 | ad−bc |
| 求逆 | 撤销变换;(AB)−1=B−1A−1,顺序倒过来 | A−1=ad−bc1[d−c−ba] |
| 转置 | 交换行和列;通常不是撤销变换 | AT=[abcd] |
| 逆与转置 | 列向量构成标准正交基时才有 A−1=AT | ATA=I |