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 新增)
  • 数据格式必须与着色器中声明的属性类型匹配
相关推荐
xhload3d10 小时前
智慧航天运载体系全生命周期监测 | 图扑数字孪生
物联网·3d·智慧城市·html5·webgl·数字孪生·可视化·工业互联网·三维建模·工控·航空航天·火箭升空·智慧航空·智慧航天·火箭发射·火箭回收
魂断蓝桥66610 小时前
使用three.js,实现微信3D小游戏系列教程,框架篇(一)
webgl·threejs·微信小游戏·3d建筑·three.js路径规划、三维a*算法、javascript三维导航,·three.js小游戏
三维搬砖者1 天前
基于 Three.js 开发三维引擎-01点类:从原理到实践
webgl·three.js
魂断蓝桥6662 天前
如何基于three.js(webgl)引擎架构,实现3D微信小游戏(第一课)
webgl·three.js·微信小游戏·three.js路径规划、三维a*算法、javascript三维导航,·three.js小游戏
康康的幸福生活2 天前
webgl2 方法解析: getContext()
webgl
庖丁解牛3 天前
3. Babylonjs 中获取相机方向相关
前端·webgl·游戏开发
康康的幸福生活3 天前
webgl2 方法解析: createBuffer()
前端·javascript·webgl
康康的幸福生活5 天前
webgl2 方法解析: shaderSource()
webgl
魂断蓝桥6665 天前
如何基于three.js(webgl)引擎架构,实现3D医院、3D园区导航,3D科室路径导航
webgl·数字孪生·threejs·3d定位、三维室内定位、3d建筑·three.js路径规划、三维a*算法、javascript三维导航,·3d医院·3d导航·园区导航