webgl2 方法解析: bufferData()

bufferData 是 WebGL2 中用于初始化或更新缓冲区对象数据存储的核心方法,它是处理顶点属性、索引和其他缓冲区类型的基础操作。

基本语法

ini 复制代码
gl.bufferData(target, size, usage);
gl.bufferData(target, data, usage);
gl.bufferData(target, srcData, usage, srcOffset, length);

参数说明

  1. target - 指定缓冲区绑定目标:

    • gl.ARRAY_BUFFER:顶点属性数据
    • gl.ELEMENT_ARRAY_BUFFER:索引数据
    • gl.COPY_READ_BUFFER/gl.COPY_WRITE_BUFFER:复制操作缓冲区
    • gl.TRANSFORM_FEEDBACK_BUFFER:变换反馈缓冲区
    • gl.UNIFORM_BUFFER:统一变量缓冲区
  2. size/data/srcData

    • 可以是指定缓冲区大小的数字
    • 或者是包含数据的 ArrayBufferTypedArrayDataView 对象
    • WebGL2 新增支持指定源数据的偏移和长度
  3. usage - 指定数据使用模式:

    • gl.STATIC_DRAW:数据内容很少更改
    • gl.DYNAMIC_DRAW:数据内容会频繁更改
    • gl.STREAM_DRAW:数据内容每次绘制都会更改
    • WebGL2 新增:gl.STATIC_READgl.DYNAMIC_READgl.STREAM_READ

WebGL2 新增特性

  1. 支持更多缓冲区类型(如统一变量缓冲区)
  2. 可以指定数据源的偏移和长度
  3. 增加了更多 usage 模式
  4. 支持使用 gl.bufferSubData 进行部分更新

使用示例

以下是一个完整的可直接运行的示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL2 三角形渲染示例</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; width: 600px; height: 400px; }
    </style>
</head>
<body>
    <canvas id="glCanvas"></canvas>
​
    <script>
        // 顶点着色器代码
        const vertexShaderSource = `#version 300 es
        in vec2 aPosition;
        in vec3 aColor;
        
        out vec3 vColor;
        
        void main() {
            gl_Position = vec4(aPosition, 0.0, 1.0);
            vColor = aColor;
        }`;
​
        // 片段着色器代码
        const fragmentShaderSource = `#version 300 es
        precision highp float;
        
        in vec3 vColor;
        out vec4 fragColor;
        
        void main() {
            fragColor = vec4(vColor, 1.0);
        }`;
​
        // 初始化WebGL2上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl2');
        
        if (!gl) {
            alert('您的浏览器不支持WebGL2');
            throw new Error('WebGL2 not supported');
        }
​
​
​
        // 编译着色器
        function compileShader(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 = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
        const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
        
        const shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader);
        gl.attachShader(shaderProgram, fragmentShader);
        gl.linkProgram(shaderProgram);
        
        if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
            console.error('着色器程序链接错误:', gl.getProgramInfoLog(shaderProgram));
        }
​
        // 定义顶点数据 (位置和颜色)
        const vertices = new Float32Array([
            // 位置 (x, y)   颜色 (r, g, b)
            -0.5, -0.5,      1.0, 0.0, 0.0,  // 左下 - 红色
             0.5, -0.5,      0.0, 1.0, 0.0,  // 右下 - 绿色
             0.0,  0.5,      0.0, 0.0, 1.0   // 顶部 - 蓝色
        ]);
​
        // 定义索引数据
        const indices = new Uint16Array([
            0, 1, 2  // 组成三角形的三个顶点索引
        ]);
​
        // 创建并绑定顶点缓冲区
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
​
        // 创建并绑定索引缓冲区
        const indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
​
        // 获取着色器中的属性位置
        const positionAttributeLocation = gl.getAttribLocation(shaderProgram, "aPosition");
        const colorAttributeLocation = gl.getAttribLocation(shaderProgram, "aColor");
​
        // 启用并设置顶点属性指针
        gl.enableVertexAttribArray(positionAttributeLocation);
        gl.vertexAttribPointer(
            positionAttributeLocation,
            2,         // 每个顶点位置有2个分量 (x, y)
            gl.FLOAT,  // 数据类型
            false,     // 是否归一化
            5 * 4,     // 步长 (5个浮点数,每个4字节)
            0          // 偏移量
        );
​
        gl.enableVertexAttribArray(colorAttributeLocation);
        gl.vertexAttribPointer(
            colorAttributeLocation,
            3,         // 每个顶点颜色有3个分量 (r, g, b)
            gl.FLOAT,  // 数据类型
            false,     // 是否归一化
            5 * 4,     // 步长 (5个浮点数,每个4字节)
            2 * 4      // 偏移量 (跳过前2个浮点数)
        );
​
        // 清除画布
        gl.clearColor(0.1, 0.1, 0.1, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);
        
        // 使用着色器程序
        gl.useProgram(shaderProgram);
        
        // 绘制三角形
        gl.drawElements(
            gl.TRIANGLES,    // 绘制模式
            indices.length, // 顶点数量
            gl.UNSIGNED_SHORT, // 索引数据类型
            0               // 偏移量
        );
    </script>
</body>
</html>

注意事项

  • 必须先绑定缓冲区才能调用 bufferData
  • 选择正确的 usage 可以提高性能
  • 大型缓冲区应考虑使用 gl.bufferStorage (WebGL2 新增)
  • 数据格式必须与着色器中声明的属性类型匹配
相关推荐
supermapsupport5 小时前
SuperMap iClient3D for WebGL 交互式栅格信息查询
webgl·supermap
八荒启·交互动画3 天前
# Web特效020—让 Web 特效真正动起来:时间循环应该怎么接
前端·webgl·网页特效·八荒启-交互动画·八荒启
八荒启·交互动画3 天前
Web特效019-Web特效的定义与边界核心算法手写一遍:先跑起来,再谈高级效果
前端·webgl·网页特效·八荒启-交互动画·八荒启
八荒启·交互动画4 天前
Web特效011—Web特效的定义与边界为什么忽快忽慢:时间、频率与采样的秘密
webgl·网页特效·八荒启-交互动画·八荒启·web特效
八荒启·交互动画4 天前
Web特效008—一个 `getContext(‘webgl‘)`,浏览器到底交出了什么?
webgl·八荒启-交互动画
xhload3d5 天前
图扑智慧工厂 | 继电器产线仿真态势管控平台
物联网·低代码·webgl·数字孪生·可视化·智慧工厂·工业互联网·hightopo
新的瑞拉公主8 天前
Unity游戏发布微信小游戏:从构建到提审
unity·webgl·微信小游戏·开放数据域
慧都小妮子10 天前
实时大屏掉帧排查:WebGL 图表库选型的 5 项可实测检查
webgl·scichart.js·实时大屏掉帧·前端图表选型
❀͜͡傀儡师10 天前
移动端 360° 商品展示方案:从 20MB 雪碧图到 800KB 丝滑视频
ffmpeg·webgl·sprite
平行云10 天前
国产GPU云渲染适配实战:驱动兼容、编码调优与多路并发
unity·ue5·webrtc·webgl·实时云渲染·云桌面·像素流送