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 新增)
  • 数据格式必须与着色器中声明的属性类型匹配
相关推荐
孪生前端4 小时前
如何用配置驱动一套 Three.js 数字孪生模板
webgl
用户83134859306984 天前
Vue+Threejs实现人物奔跑场景
vue.js·webgl·three.js
元气少女小圆丶5 天前
unity发布web嵌入到前端页面的接受参数
前端·unity·webgl
WebGIS开发7 天前
WebGIS开发进阶教程①:WebGL坐标系
gis·webgl·gis开发
虚焦像素_8 天前
MapLibre GL 实战:一套引擎搞定 2D 平面与 3D 球面
webgl
山河木马10 天前
GPU自动处理专题4-填充覆盖区域(光栅化)
javascript·webgl·计算机图形学
智商偏低10 天前
WebGL 百万线段高性能 Demo(批量绘制,无循环绘制)
webgl
weixin_4368040712 天前
毒蘑菇性能测试增强版 - 毒蘑菇性能测试 - 在线 WebGL GPU 帧率压力测试工具
webgl
山河木马13 天前
GPU自动处理专题3-NDC怎么映射成屏幕像素坐标(视口变换)
javascript·webgl·图形学
山河木马13 天前
GPU自动处理专题2-NDC是什么(透视除法)
javascript·webgl·计算机图形学