第4章:矩阵基础与线性变换

好,咱们今天来聊聊矩阵。说实话,我第一次接触矩阵的时候,脑子里全是问号——这玩意儿不就是一堆数字排排坐吗?后来做动画做多了才明白,矩阵其实是图形变换的「万能遥控器」。你想想看,屏幕上那个小方块怎么放大、怎么旋转、怎么歪着扭着,背后都是矩阵在干活。

4.1 2x2矩阵的定义

先看最简单的2x2矩阵长什么样:

[ a  b ]
[ c  d ]

嗯,就四个数字。但别小看它。每个数字都代表一个「指令」。我个人习惯把矩阵想象成一个函数机器——你扔进去一个坐标(x, y),它吐出来一个新坐标(x', y')。

具体怎么算的?看公式:

x' = a*x + b*y
y' = c*x + d*y

说白了就是线性组合。原来那个点的x和y,分别乘以不同的系数,再加起来。这就是线性变换的本质。

核心理解:矩阵的每一列,其实代表变换后的基向量。第一列(a, c)是x轴基向量(1,0)变换后的位置,第二列(b, d)是y轴基向量(0,1)变换后的位置。

我在项目中遇到过一个问题:为什么有时候矩阵算出来的坐标会超出屏幕?后来发现是忘了考虑平移。2x2矩阵只能处理线性变换,平移得靠3x3矩阵。这个后面会讲,先记住这个坑。

4.2 缩放矩阵

缩放是最直观的变换。你想把一个图形拉宽或压扁,用缩放矩阵:

[ sx  0  ]
[ 0   sy ]

sx是x方向的缩放倍数,sy是y方向的。如果sx=2,那图形在x方向就变成两倍宽。

举个例子:点(3, 4)经过sx=2, sy=0.5的缩放:

x' = 2*3 + 0*4 = 6
y' = 0*3 + 0.5*4 = 2

结果变成(6, 2)。x拉长了,y压扁了。

小技巧:如果sx和sy相等,就是等比缩放。如果不相等,图形就会变形。做动画时,我经常用不等比缩放来模拟「挤压」效果,比如弹跳球落地那一瞬间的压扁。

4.3 旋转矩阵

旋转稍微复杂一点,涉及三角函数。绕原点逆时针旋转θ角度的矩阵是:

[ cosθ  -sinθ ]
[ sinθ   cosθ ]

为什么会这样?你想想看,点(1,0)旋转θ后变成(cosθ, sinθ),点(0,1)旋转θ后变成(-sinθ, cosθ)。这两列正好就是旋转矩阵的两列。

来个实际例子:点(1, 0)旋转90度(θ=90°):

cos90° = 0, sin90° = 1
x' = 0*1 + (-1)*0 = 0
y' = 1*1 + 0*0 = 1

结果(0, 1),完美。从x轴正方向转到了y轴正方向。

注意:CSS和Canvas中的旋转方向是顺时针的,而数学上默认是逆时针。我曾经因为这个搞反了旋转方向,调试了半天才发现是角度符号的问题。建议统一用数学标准,到具体平台再转换。

4.4 切变矩阵

切变可能比较陌生,但效果你肯定见过——就是那种把正方形拉成平行四边形的感觉。x方向切变矩阵:

[ 1  shx ]
[ 0   1  ]

shx是切变系数。点(x, y)变换后变成(x + shx*y, y)。你看,y坐标不变,x坐标根据y的值偏移了。y越大,偏移越多。

y方向切变类似:

[ 1   0  ]
[ shy  1 ]

点(x, y)变成(x, shy*x + y)。

我记得有一次做翻页动画,想模拟纸张被拉扯的效果,就是用切变矩阵实现的。配合缩放,效果还挺自然。

4.5 矩阵乘法与复合变换

单个变换太单调了。实际做动画,往往要缩放+旋转+切变一起上。这时候就需要矩阵乘法。

两个2x2矩阵相乘的规则:

[ a  b ]   [ e  f ]   [ a*e+b*g  a*f+b*h ]
[ c  d ] * [ g  h ] = [ c*e+d*g  c*f+d*h ]

说白了就是「行乘列」。左边矩阵的行,依次乘右边矩阵的列,加起来。

重点来了:矩阵乘法不满足交换律。A*B不等于B*A。顺序很重要。

实战经验:先旋转再平移,和先平移再旋转,结果完全不同。我刚开始做动画时,经常搞混顺序,导致图形飞到奇怪的位置。后来养成了一个习惯:从右往左读变换顺序。比如矩阵M = T * R,意思是先应用R(旋转),再应用T(平移)。

举个复合变换的例子:先缩放(sx=2, sy=1),再旋转45度。

缩放矩阵S:

[ 2  0 ]
[ 0  1 ]

旋转矩阵R(cos45°≈0.707, sin45°≈0.707):

[ 0.707  -0.707 ]
[ 0.707   0.707 ]

复合矩阵M = R * S:

[ 0.707*2 + (-0.707)*0   0.707*0 + (-0.707)*1 ]   [ 1.414  -0.707 ]
[ 0.707*2 + 0.707*0      0.707*0 + 0.707*1    ] = [ 1.414   0.707 ]

这个复合矩阵就同时包含了缩放和旋转的效果。

优化建议:如果多个变换要应用到大量顶点上,先把所有矩阵乘成一个复合矩阵,再一次性应用到每个顶点。这样能省掉大量重复计算。我在做粒子系统时,就是先把所有变换合并,性能提升很明显。

4.6 总结一下

这一章的内容,说白了就是三件事:

  • 矩阵是变换的数学表达——四个数字控制一个线性变换
  • 三种基本变换——缩放、旋转、切变,各有各的矩阵形式
  • 复合变换靠矩阵乘法——顺序决定结果,从右往左读

嗯,到这里矩阵的基础就打好了。下一章我们会把这些矩阵应用到实际的动画坐标变换中,到时候你就能看到这些数字是怎么让图形动起来的。

记住一句话:矩阵不是用来背的,是用来理解变换的。你只要理解了每一列代表基向量的去向,矩阵在你眼里就不再是一堆数字,而是一个活生生的变换指令集。