🎨 Phase 0.4: 手写第一个裸 WebGL 程序

从零开始,不用任何库,渲染一个彩色三角形

💡 核心目标

体验完整的 WebGL 编程流程:

1️⃣ 创建 WebGL 上下文 → 2️⃣ 编写着色器(GLSL)→ 3️⃣ 准备顶点数据 → 4️⃣ Bind → Config → Draw

理解 Three.js 在背后替你做了什么:所有这些底层操作,Three.js 都自动帮你完成了!

1
创建上下文
2
编写着色器
3
准备数据
4
绘制三角形

🎨 顶点颜色

📐 三角形变换

🔄 动画控制

📝 核心代码解析

// ========== 步骤 1: 创建 WebGL 上下文 ==========
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');

// ========== 步骤 2: 编写着色器 ==========
// 顶点着色器(GLSL)- 计算顶点位置
const vertexShaderSource = `
    attribute vec3 aPosition;  // 顶点坐标
    attribute vec3 aColor;     // 顶点颜色
    varying vec3 vColor;       // 传递给片元着色器
    uniform float uRotation;   // 旋转角度
    uniform float uScale;      // 缩放比例

    void main() {
        // 旋转矩阵
        float c = cos(uRotation);
        float s = sin(uRotation);
        mat2 rotation = mat2(c, s, -s, c);

        // 应用变换
        vec2 pos = rotation * aPosition.xy * uScale;
        gl_Position = vec4(pos, 0.0, 1.0);

        // 传递颜色
        vColor = aColor;
    }
`;

// 片元着色器(GLSL)- 计算像素颜色
const fragmentShaderSource = `
    precision mediump float;
    varying vec3 vColor;  // 从顶点着色器接收(已插值)

    void main() {
        gl_FragColor = vec4(vColor, 1.0);
    }
`;

// ========== 步骤 3: 准备顶点数据 ==========
const vertices = new Float32Array([
    // x,    y,    z
     0.0,  0.5,  0.0,  // 顶点 1(顶部)
    -0.5, -0.5,  0.0,  // 顶点 2(左下)
     0.5, -0.5,  0.0   // 顶点 3(右下)
]);

const colors = new Float32Array([
    // R,   G,   B
    1.0, 0.0, 0.0,  // 红色
    0.0, 1.0, 0.0,  // 绿色
    0.0, 0.0, 1.0   // 蓝色
]);

// ========== 步骤 4: Bind → Config → Draw ==========
// 创建缓冲区
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 绘制
gl.drawArrays(gl.TRIANGLES, 0, 3);  // 绘制 3 个顶点组成的三角形