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 新增)
  • 数据格式必须与着色器中声明的属性类型匹配
相关推荐
刘一说1 天前
腾讯位置服务JavaScript API GL地图组件库深度解析:Vue生态中的地理空间可视化利器
javascript·vue.js·信息可视化·webgl·webgis
烛阴1 天前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
WebGISer_白茶乌龙桃2 天前
Cesium实现“悬浮岛”式,三维立体的行政区划
javascript·vue.js·3d·web3·html5·webgl
烛阴2 天前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js
WebGISer_白茶乌龙桃3 天前
Vue3 + Mapbox 加载 SHP 转换的矢量瓦片 (Vector Tiles)
javascript·vue.js·arcgis·webgl
ThreePointsHeat7 天前
Unity WebGL打包后启动方法,部署本地服务器
unity·游戏引擎·webgl
林枫依依8 天前
电脑配置流程(WebGL项目)
webgl
冥界摄政王10 天前
CesiumJS学习第四章 替换指定3D建筑模型
3d·vue·html·webgl·js·cesium
温宇飞12 天前
高效的线性采样高斯模糊
javascript·webgl
冥界摄政王13 天前
Cesium学习第一章 安装下载 基于vue3引入Cesium项目开发
vue·vue3·html5·webgl·cesium