WebGL基础教程(十三) :玩转矩阵,从 0 到 1 玩转 3D 动画(新手也能秒懂矩阵变换)

还在被 WebGL 的矩阵搞得头大?想不通平移、旋转、缩放的矩阵怎么写,更不懂复合变换的顺序?

今天这篇教程,全程围绕标准矩阵乘法展开,从基础矩阵原理到实战动画,手把手教你用纯矩阵写法实现 WebGL 平移、旋转、缩放,甚至用 gl-matrix 库实现炫酷的复合动画,新手也能跟着敲出效果,彻底搞懂矩阵在 WebGL 中的核心作用。

1.先搞懂:WebGL + 矩阵 = 3D 图形的灵魂

WebGL(Web Graphics Library)是浏览器原生的 3D/2D 渲染 API,无需插件、直接调用 GPU 加速 ------ 但想要玩转 WebGL 动画,矩阵乘法是绕不开的核心!

核心优势(标准矩阵版)

  • 矩阵统一变换逻辑:平移、旋转、缩放都通过「矩阵 × 顶点坐标」实现,完全符合 GPU 渲染规范
  • GPU 友好:矩阵运算可被 GPU 高效并行处理,动画更丝滑
  • 复合变换超灵活:多个矩阵相乘就能实现「平移 + 旋转 + 缩放」组合效果,扩展无压力

2.WebGL + 矩阵工作原理

WebGL 基于 OpenGL ES,核心是着色器;而矩阵是连接「JavaScript 逻辑」和「GPU 渲染」的桥梁:

  1. 开发者在 CPU 端构建变换矩阵(平移 / 旋转 / 缩放 / 复合)
  2. 将 4x4 矩阵传入顶点着色器的 uniform 变量
  3. GPU 通过「矩阵 × 顶点坐标」的乘法运算,计算顶点最终位置并完成渲染

关键:WebGL 中所有变换的标准写法是 gl_Position = 变换矩阵 * 顶点坐标,而非直接修改顶点 x/y 分量!


2.1 平移变换

平移是最基础的仿射变换,用 4x4 矩阵表示后,能和其他变换无缝组合!

平移矩阵原理(新手秒懂)

在计算机图形学中,平移的数学原理通过齐次坐标 + 4x4 矩阵实现:

  • 三维点表示为齐次坐标 (x,y,z,1)
  • 三维平移矩阵(WebGL 标准 4x4 形式):

text

复制代码
[ 1  0  0  tx ]
[ 0  1  0  ty ]
[ 0  0  1  tz ]
[ 0  0  0  1  ]

矩阵乘法计算过程:

对三维点 (x,y,z,1) 执行矩阵乘法:

plaintext

复制代码
x' = 1*x + 0*y + 0*z + tx*1 = x + tx
y' = 0*x + 1*y + 0*z + ty*1 = y + ty
z' = 0*x + 0*y + 1*z + tz*1 = z + tz
w' = 0*x + 0*y + 0*z + 1*1  = 1

注:WebGL 中即使处理 2D 图形,也统一使用 4x4 矩阵(z/tz 设为 0),这是 GPU 原生支持的标准格式。

实战:纯矩阵实现平移动画(代码可直接跑)

html

预览

复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>🔥WebGL矩阵实战:平移的红色三角形</title>
    <style>
        canvas { border: 2px solid #ff4400; display: block; margin: 20px auto; border-radius: 8px; }
    </style>
</head>
<body>
    <canvas id="glCanvas" width="500" height="500"></canvas>

    <script>
        // 1. 获取Canvas和WebGL上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl');

        if (!gl) {
            alert('😭您的浏览器不支持WebGL!换Chrome/Firefox试试');
            throw new Error('WebGL not supported');
        }

        // 2. 设置黑色背景
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        // 3. 着色器(核心:纯矩阵乘法实现平移)
        const vertexShaderSource = `
            attribute vec4 a_Position;
            uniform mat4 u_TranslateMatrix; // 4x4平移矩阵
            void main() {
                // WebGL标准写法:矩阵 × 顶点坐标
                gl_Position = u_TranslateMatrix * a_Position;
            }
        `;

        const fragmentShaderSource = `
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
            }
        `;

        // 4. 封装着色器创建函数
        function createShader(gl, source, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('❌着色器编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            return shader;
        }

        // 5. 创建并链接程序
        const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
        const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);

        // 6. 顶点数据(三角形)
        const vertices = new Float32Array([
            -0.2, -0.2, 0.0,
            0.2, -0.2, 0.0,
            0.0, 0.2, 0.0
        ]);

        // 7. 绑定顶点数据到GPU
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        const a_Position = gl.getAttribLocation(program, 'a_Position');
        gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(a_Position);

        // 8. 矩阵平移核心:构建4x4平移矩阵
        const u_TranslateMatrix = gl.getUniformLocation(program, 'u_TranslateMatrix');
        const translateMatrix = new Float32Array(16); // WebGL矩阵格式(16个元素的Float32Array)
        let tx = 0.0; // 平移量x
        const step = 0.02;

        // 构建4x4平移矩阵的函数(WebGL列主序)
        function setTranslateMatrix(matrix, tx, ty, tz) {
            matrix.set([
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                tx, ty, tz, 1
            ]);
        }

        // 9. 动画循环
        function animate() {
            // 更新平移量
            tx += step;
            if (tx > 1.0) tx = -1.0;

            // 构建4x4平移矩阵
            setTranslateMatrix(translateMatrix, tx, 0.0, 0.0);

            // 传递矩阵给着色器(false=不转置,WebGL默认列主序)
            gl.uniformMatrix4fv(u_TranslateMatrix, false, translateMatrix);

            // 清屏+绘制
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLES, 0, 3);

            requestAnimationFrame(animate);
        }

        animate();
    </script>
</body>
</html>

效果

红色三角形沿 x 轴平移,本质是不断更新 4x4 平移矩阵的 tx 分量,GPU 通过「矩阵 × 顶点」计算新位置!


2.2 旋转变换

旋转的核心是「4x4 旋转矩阵」,纯矩阵乘法写法更易和其他变换组合!

旋转矩阵原理(重点!)

二维点绕原点逆时针旋转 θ 角的 4x4 矩阵(WebGL 标准格式):

text

复制代码
[ cosθ  -sinθ  0  0 ]
[ sinθ   cosθ  0  0 ]
[ 0      0     1  0 ]
[ 0      0     0  1 ]

矩阵乘法计算过程:

对二维点 (x,y)(齐次坐标 (x,y,0,1))执行矩阵乘法:

plaintext

复制代码
x' = cosθ * x + (-sinθ) * y + 0 * 0 + 0 * 1 = x*cosθ - y*sinθ
y' = sinθ * x + cosθ * y + 0 * 0 + 0 * 1 = x*sinθ + y*cosθ
z' = 0 * x + 0 * y + 1 * 0 + 0 * 1 = 0
w' = 0 * x + 0 * y + 0 * 0 + 1 * 1 = 1

矩阵乘法结果等价于:

plaintext

复制代码
x' = x*cosθ - y*sinθ
y' = x*sinθ + y*cosθ

关键:矩阵形式无需在着色器中写三角函数,只需传递完整矩阵,更符合 GPU 渲染规范!

实战:纯矩阵实现旋转动画

html

预览

复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>🔥WebGL矩阵实战:旋转的红色三角形</title>
    <style>
        canvas { border: 2px solid #ff4400; display: block; margin: 20px auto; border-radius: 8px; }
    </style>
</head>
<body>
    <canvas id="glCanvas" width="500" height="500"></canvas>

    <script>
        // 1. 获取上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl');
        if (!gl) {
            alert('😭换Chrome/Firefox试试!');
            throw new Error('WebGL not supported');
        }
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        // 2. 着色器(核心:纯矩阵乘法实现旋转)
        const vertexShaderSource = `
            attribute vec4 a_Position;
            uniform mat4 u_RotateMatrix; // 4x4旋转矩阵
            void main() {
                // WebGL标准写法:旋转矩阵 × 顶点坐标
                gl_Position = u_RotateMatrix * a_Position;
            }
        `;

        const fragmentShaderSource = `
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
            }
        `;

        // 3. 创建着色器+程序(复用)
        function createShader(gl, source, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('❌编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            return shader;
        }
        const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
        const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);

        // 4. 顶点数据
        const vertices = new Float32Array([
            0.0, 0.5, 0.0,
            -0.5, -0.5, 0.0,
            0.5, -0.5, 0.0
        ]);
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        const a_Position = gl.getAttribLocation(program, 'a_Position');
        gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(a_Position);

        // 5. 旋转矩阵核心:构建4x4绕Z轴旋转矩阵
        const u_RotateMatrix = gl.getUniformLocation(program, 'u_RotateMatrix');
        const rotateMatrix = new Float32Array(16);
        let angle = 0.0; // 旋转角度θ(弧度)

        // 构建4x4绕Z轴旋转矩阵的函数
        function setRotateZMatrix(matrix, angle) {
            const cos = Math.cos(angle);
            const sin = Math.sin(angle);
            matrix.set([
                cos, -sin, 0, 0,
                sin,  cos, 0, 0,
                0,    0,  1, 0,
                0,    0,  0, 1
            ]);
        }

        // 6. 动画循环
        function animateRotate() {
            angle += 0.02;

            // 构建4x4旋转矩阵
            setRotateZMatrix(rotateMatrix, angle);

            // 传递旋转矩阵给着色器
            gl.uniformMatrix4fv(u_RotateMatrix, false, rotateMatrix);

            // 绘制
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLES, 0, 3);

            requestAnimationFrame(animateRotate);
        }

        animateRotate();
    </script>
</body>
</html>

效果

三角形绕原点旋转,本质是不断更新 4x4 旋转矩阵的 cosθ/sinθ 分量,GPU 自动完成「矩阵 × 顶点」运算!


2.3 缩放变换

缩放是改变图形大小的核心变换,同样通过 4x4 矩阵乘法实现,是复合变换的重要组成部分!

缩放矩阵原理(核心!)

二维点沿 x/y 轴缩放的 4x4 矩阵(WebGL 标准格式):

text

复制代码
[ sx  0   0   0 ]
[ 0   sy  0   0 ]
[ 0   0   sz  0 ]
[ 0   0   0   1 ]
  • sx:x 轴缩放因子(>1 放大,<1 缩小,负数翻转)
  • sy:y 轴缩放因子
  • sz:z 轴缩放因子(2D 场景设为 1)

矩阵乘法计算过程:

对二维点 (x,y)(齐次坐标 (x,y,0,1))执行矩阵乘法:

plaintext

复制代码
x' = sx * x + 0 * y + 0 * 0 + 0 * 1 = x * sx
y' = 0 * x + sy * y + 0 * 0 + 0 * 1 = y * sy
z' = 0 * x + 0 * y + sz * 0 + 0 * 1 = 0 (2D场景sz=1)
w' = 0 * x + 0 * y + 0 * 0 + 1 * 1 = 1

矩阵乘法结果等价于:

plaintext

复制代码
x' = x * sx
y' = y * sy

关键:缩放矩阵的核心是对角线上的缩放因子,非对角线元素均为 0,保证仅改变大小不改变位置(绕原点缩放)。

实战:纯矩阵实现缩放动画

html

预览

复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>🔥WebGL矩阵实战:缩放的红色三角形</title>
    <style>
        canvas { border: 2px solid #ff4400; display: block; margin: 20px auto; border-radius: 8px; }
    </style>
</head>
<body>
    <canvas id="glCanvas" width="500" height="500"></canvas>

    <script>
        // 1. 获取上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl');
        if (!gl) {
            alert('😭您的浏览器不支持WebGL!换Chrome/Firefox试试');
            throw new Error('WebGL not supported');
        }
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        // 2. 着色器(核心:纯矩阵乘法实现缩放)
        const vertexShaderSource = `
            attribute vec4 a_Position;
            uniform mat4 u_ScaleMatrix; // 4x4缩放矩阵
            void main() {
                // WebGL标准写法:缩放矩阵 × 顶点坐标
                gl_Position = u_ScaleMatrix * a_Position;
            }
        `;

        const fragmentShaderSource = `
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
            }
        `;

        // 3. 创建着色器+程序(复用)
        function createShader(gl, source, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('❌编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            return shader;
        }
        const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
        const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);

        // 4. 顶点数据
        const vertices = new Float32Array([
            0.0, 0.5, 0.0,
            -0.5, -0.5, 0.0,
            0.5, -0.5, 0.0
        ]);
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        const a_Position = gl.getAttribLocation(program, 'a_Position');
        gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(a_Position);

        // 5. 缩放矩阵核心:构建4x4缩放矩阵
        const u_ScaleMatrix = gl.getUniformLocation(program, 'u_ScaleMatrix');
        const scaleMatrix = new Float32Array(16);
        let scaleFactor = 1.0; // 缩放因子
        const step = 0.01;     // 缩放步长
        let isEnlarging = true; // 放大/缩小标记

        // 构建4x4缩放矩阵的函数
        function setScaleMatrix(matrix, sx, sy, sz) {
            matrix.set([
                sx, 0,  0,  0,
                0,  sy, 0,  0,
                0,  0,  sz, 0,
                0,  0,  0,  1
            ]);
        }

        // 6. 动画循环
        function animateScale() {
            // 更新缩放因子(来回缩放)
            if (isEnlarging) {
                scaleFactor += step;
                if (scaleFactor >= 2.0) isEnlarging = false;
            } else {
                scaleFactor -= step;
                if (scaleFactor <= 0.5) isEnlarging = true;
            }

            // 构建4x4缩放矩阵(x/y轴等比缩放)
            setScaleMatrix(scaleMatrix, scaleFactor, scaleFactor, 1.0);

            // 传递缩放矩阵给着色器
            gl.uniformMatrix4fv(u_ScaleMatrix, false, scaleMatrix);

            // 清屏+绘制
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLES, 0, 3);

            requestAnimationFrame(animateScale);
        }

        animateScale();
    </script>
</body>
</html>

效果

三角形绕原点在 0.5 倍~2 倍之间来回缩放,本质是不断更新 4x4 缩放矩阵的 sx/sy 分量,GPU 自动完成「矩阵 × 顶点」运算!


2.4 矩阵进阶:平移 + 旋转 + 缩放复合变换

手动组合多个矩阵容易出错?gl-matrix 库可一键完成「平移 + 旋转 + 缩放」的矩阵乘法,是工业级开发的首选方案!

gl-matrix 库的核心优势

  • 封装所有 4x4 矩阵运算:mat4.translate()/mat4.rotateZ()/mat4.scale() 直接生成变换矩阵
  • 自动处理矩阵乘法:复合变换只需按顺序调用 API,无需手动计算矩阵相乘
  • 性能优化:针对 WebGL 做了 GPU 适配,动画更丝滑

💻 实战:平移 + 旋转 + 缩放复合动画

html

预览

复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>🔥WebGL矩阵进阶:平移+旋转+缩放复合动画</title>
    <style>
        canvas { border: 2px solid #ff4400; display: block; margin: 20px auto; border-radius: 8px; }
    </style>
    <!-- 引入gl-matrix库(直接用CDN) -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
</head>
<body>
    <canvas id="glCanvas" width="500" height="500"></canvas>

    <script>
        // 1. 获取上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl');
        if (!gl) {
            alert('😭您的浏览器不支持WebGL!换Chrome/Firefox试试');
            throw new Error('WebGL not supported');
        }
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        // 2. 着色器(核心:接收4x4复合变换矩阵)
        const vertexShaderSource = `
            attribute vec4 a_Position;
            uniform mat4 u_ModelMatrix; // 复合变换矩阵(平移+旋转+缩放)
            void main() {
                // 标准写法:复合矩阵 × 顶点坐标
                gl_Position = u_ModelMatrix * a_Position;
            }
        `;

        const fragmentShaderSource = `
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
            }
        `;

        // 3. 创建着色器+程序(复用)
        function createShader(gl, source, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('❌编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            return shader;
        }
        const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
        const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);

        // 4. 顶点数据
        const vertices = new Float32Array([
            0.0, 0.5, 0.0,
            -0.5, -0.5, 0.0,
            0.5, -0.5, 0.0
        ]);
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        const a_Position = gl.getAttribLocation(program, 'a_Position');
        gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(a_Position);

        // 5. 复合矩阵核心(重点!)
        const u_ModelMatrix = gl.getUniformLocation(program, 'u_ModelMatrix');
        const modelMatrix = mat4.create(); // 创建单位矩阵(初始无变换)
        let tx = 0.0;         // 平移量x
        let angle = 0.0;      // 旋转角度θ
        let scaleFactor = 1.0;// 缩放因子
        let isEnlarging = true;

        function animateWithMatrix() {
            // 1. 重置为单位矩阵(每次循环清空变换)
            mat4.identity(modelMatrix);

            // 2. 按顺序执行复合变换(⚠️ 顺序决定最终效果!)
            // 第一步:缩放(先缩放,保证旋转/平移基于原始大小)
            mat4.scale(modelMatrix, modelMatrix, [scaleFactor, scaleFactor, 1.0]);
            // 第二步:旋转(再旋转,保证平移基于旋转后的方向)
            mat4.rotateZ(modelMatrix, modelMatrix, angle);
            // 第三步:平移(最后平移,保证整体位置移动)
            mat4.translate(modelMatrix, modelMatrix, [tx, 0.0, 0.0]);

            // 3. 更新参数
            tx += 0.015;
            if (tx > 1.0) tx = -1.0;
            angle += 0.02;
            // 缩放参数更新
            if (isEnlarging) {
                scaleFactor += 0.005;
                if (scaleFactor >= 1.5) isEnlarging = false;
            } else {
                scaleFactor -= 0.005;
                if (scaleFactor <= 0.7) isEnlarging = true;
            }

            // 4. 传递复合矩阵给GPU
            gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix);

            // 5. 绘制
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLES, 0, 3);

            requestAnimationFrame(animateWithMatrix);
        }

        animateWithMatrix();
    </script>
</body>
</html>

效果

三角形同时完成「沿 x 轴平移 + 绕原点旋转 + 0.7~1.5 倍缩放」的复合动画,gl-matrix 自动完成所有矩阵乘法运算,代码简洁且高效!


矩阵核心知识点(必记!)

  1. 变换顺序≠乘法交换律 :矩阵乘法不满足交换律,变换顺序直接决定最终效果(推荐顺序:缩放 → 旋转 → 平移):
    • 缩放→旋转→平移:图形先调整大小,再旋转方向,最后移动位置(最符合直觉)
    • 平移→旋转→缩放:图形先移动,再旋转,最后缩放(会导致平移距离也被缩放)
  2. 单位矩阵是基础mat4.identity() 生成单位矩阵(无变换),是所有矩阵变换的起点
  3. 矩阵格式要正确 :WebGL 中矩阵必须是 Float32Array 类型的 16 个元素(列主序),传递时 gl.uniformMatrix4fv 的第二个参数必须为 false

🎁 新手矩阵避坑指南

  1. 先跑通代码,再理解矩阵:不用一开始死磕矩阵乘法,先改 tx/angle/scaleFactor 数值,看动画变化,直观理解矩阵作用
  2. 拒绝手动改顶点坐标:WebGL 标准写法是「矩阵 × 顶点」,直接修改 x/y 分量会丧失 GPU 并行计算优势
  3. 优先用 gl-matrix 库:实际开发中避免手动拼矩阵,减少 90% 错误,专注业务逻辑
  4. 注意缩放中心:默认缩放绕原点进行,若需绕自定义点缩放,需先平移到原点→缩放→平移回原位置

3.矩阵核心总结

  1. WebGL 动画的本质:CPU 端构建 4x4 变换矩阵 → 传递给着色器 → GPU 执行「矩阵 × 顶点坐标」计算新位置
  2. 三大基础变换矩阵:
    • 平移:第四列前三个元素为平移量(tx/ty/tz)
    • 旋转:左上角 2x2 矩阵为 cosθ/sinθ 组合(绕 Z 轴)
    • 缩放:对角线上的元素为缩放因子(sx/sy/sz)
  3. 实战技巧:用 gl-matrix 库简化矩阵操作,严格遵守「缩放→旋转→平移」的复合变换顺序,注意矩阵乘法无交换律

💡 下期预告

掌握矩阵后,我们解锁更炫酷的矩阵玩法:✅ 透视矩阵(实现 3D 景深效果)✅ 视图矩阵(模拟相机移动)✅ 模型视图投影矩阵(MVP 矩阵):工业级 3D 渲染核心

关注我,下期手把手教你用矩阵打造真正的 3D 场景,新手也能轻松拿捏🎊!

相关推荐
乘云数字DATABUFF3 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--4 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森4 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜5 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB6 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode8 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220708 天前
如何搭建本地yum源(上)
运维
ping某9 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
大树8811 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠11 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql