第一次接触WebGL时,我对着色器里突然冒出的mat4类型一脸懵——为什么画个三角形要动用矩阵这种"高端"数学工具?直到亲手用三角函数实现旋转动画时,才明白矩阵的价值。当时我写了30多行代码计算顶点位置,结果换个旋转角度就得重写整个逻辑,而隔壁用矩阵的同学只需修改4个数字。
矩阵本质上是数学公式的打包工具。比如要让物体旋转θ角度,传统方法需要为每个顶点计算:
javascript复制x' = x*cosθ - y*sinθ
y' = x*sinθ + y*cosθ
当同时需要旋转、平移、缩放时,公式会复杂到怀疑人生。而矩阵把这些计算抽象成统一格式:
glsl复制gl_Position = matrix * position;
这种统一性带来三个实际好处:
提示:现代GPU有专门的矩阵运算单元,4x4矩阵乘法能在1个时钟周期完成
让我们用乐高思维拆解旋转矩阵。假设要把点P(x,y)旋转θ度到P'(x',y'),根据三角函数可得:
code复制x' = x*cosθ - y*sinθ
y' = x*sinθ + y*cosθ
这其实暗藏矩阵乘法的结构:
code复制[ x' ] [ cosθ -sinθ ] [ x ]
[ y' ] = [ sinθ cosθ ] [ y ]
这就是2D旋转矩阵的由来!3D版本同理,比如绕Z轴旋转时:
javascript复制const mat = [
cosθ, sinθ, 0, 0,
-sinθ,cosθ, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
平移公式x'=x+Δx看似简单,却有个反直觉的设计——必须用4x4矩阵。因为3x3矩阵无法表示加法项,就像一次函数y=kx+b无法用纯乘法表示。解决方案是:
javascript复制[
1, 0, 0, Δx,
0, 1, 0, Δy,
0, 0, 1, Δz,
0, 0, 0, 1
]
这样矩阵乘法后第4行的1会"激活"Δx项,相当于完成加法。
在JavaScript中创建矩阵后,需要正确传递给着色器。常见坑点包括:
javascript复制// 正确方式:使用列主序存储
const matrix = new Float32Array([
m11, m21, m31, m41, // 第一列
m12, m22, m32, m42, // 第二列
m13, m23, m33, m43, // 第三列
m14, m24, m34, m44 // 第四列
]);
// 传递到着色器
gl.uniformMatrix4fv(location, false, matrix);
特别注意第二个参数transpose必须为false,WebGL只接受列主序数据。
当需要先旋转后平移时,矩阵乘法顺序很重要:
javascript复制const finalMatrix = mat4.multiply(
mat4.create(),
translationMatrix,
rotationMatrix
);
因为矩阵乘法不满足交换律,reverseOrder=true会导致物体绕世界原点旋转而非自身中心点。
频繁创建新矩阵会触发垃圾回收,导致卡顿。推荐:
javascript复制// 初始化时创建池
const matrixPool = {
projection: mat4.create(),
view: mat4.create(),
model: mat4.create()
};
// 渲染循环中复用
mat4.rotateZ(matrixPool.model, angle);
实测显示,复用矩阵能使60fps场景的GC时间减少83%。
当变换出错时,可以用这个着色器片段快速定位问题:
glsl复制// 片段着色器中添加
if(u_DebugMode > 0.5) {
float shade = mod(gl_FragCoord.x + gl_FragCoord.y, 10.0);
if(shade < 5.0) discard;
}
这会生成网格线,清晰显示实际变换效果。
让我们实现一个行星系统:中心恒星自转,行星绕恒星公转的同时自转。关键代码结构:
javascript复制// 恒星变换
mat4.identity(modelMatrix);
mat4.rotateY(modelMatrix, starRotation);
// 行星变换
mat4.identity(modelMatrix);
mat4.translate(modelMatrix, [orbitRadius, 0, 0]);
mat4.rotateY(modelMatrix, planetRotation);
mat4.scale(modelMatrix, [0.5, 0.5, 0.5]);
这个案例完美展示了矩阵堆叠的威力——每个变换都是独立的数学操作,却能组合出复杂效果。
理解矩阵就像获得图形编程的"超能力"。最初可能需要反复查阅矩阵公式,但当你习惯这种思维方式后,会发现三维空间操控变得如此直观。我的突破时刻是第一次用矩阵实现摄像机跟随——原来游戏引擎里的神奇效果,底层不过是几个矩阵的优雅舞蹈。