WebGL 绘制多个点


webGL 提供了缓冲区对象(buffer object), 可以一次性向着色器传入多个顶点的数据. 缓冲区对象是webGL系统中的一块内存区域, 我们可以一次性向缓冲区对象填充大量的顶点数据, 然后这些数据保存在其中, 供顶点着色器使用.

源码参考

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>绘制多个点</title>
 <script src="../lib/webgl-utils.js"></script>
 <script src="../lib/webgl-debug.js"></script>
 <script src="../lib/cuon-utils.js"></script>
 <script src="main.js"></script>
</head>
<body onload="main()">
 <canvas id="webgl" width="400" height="400">
    你的浏览器暂时不支持canvas, 请升级到最新版本
 </canvas>
</body>
</html>
// 顶点着色器
var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    'gl_Position = a_Position;\n' +
    'gl_PointSize = 80.0;\n' +
    '}\n';

// 片元着色器
var FSHADER_SOURCE =
    'precision mediump float;\n' +
    'uniform vec4 u_FragColor;\n' +
    'void main() {\n' +
    'gl_FragColor = u_FragColor;\n' +
    '}\n';

// 主程序
function main() {
    var canvas = document.getElementById('webgl');
    var gl = getWebGLContext(canvas);
    if (!gl) {
        console.log('未能获取WebGL的呈现上下文');
        return;
    }

    // 初始化着色器
    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('初始化着色器失败');
        return;
    }

    // 缓冲区
    var n = initVertexBuffers(gl);
    if (n < 0) {
        console.log('未能设置顶点的位置');
        return;
    }

    // 改变点的颜色
    var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
    if (!u_FragColor) {
        console.log('获取u_FragColor的存储位置失败');
        return;
    }
    gl.uniform4f(u_FragColor, 0.5, 0.5, 1.0, 1.0);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.POINTS, 0, n);

    function initVertexBuffers(gl) {
        var vertices = new Float32Array([
            -0.5, 0.5,
            0.5, 0.5,
            -0.2, -0.5,
            0.2, -0.5,
            0.0, -0.5,
        ]);
        var n = vertices.length / 2;
        // 1. 创建缓冲区对象
        var vertexBuffer = gl.createBuffer();
        if (!vertexBuffer) {
            console.log('创建缓冲区对象失败');
            return -1;
        }
        // 2. 绑定缓冲区对象
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        // 3. 向缓冲区中写入数据
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

        var a_Position = gl.getAttribLocation(gl.program, 'a_Position');

        if (a_Position < 0) {
            console.log('未能获取a_Position的存储位置');
            return -1;
        }
        // 4. 将缓冲区对象分配给 attribute 变量
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
        // 5. 开启 attribute 变量
        gl.enableVertexAttribArray(a_Position);
        return n;
    }
}

在 initVertexBuffer() 函数中利用缓冲区对象向顶点着色器传输多个顶点的数据,同时在 gl.drawArrays()函数提供了需要的顶点个数.

使用缓冲区对象向顶点着色器传入多个顶点的数据, 需要遵循以下步骤:

  1. 创建缓冲区对象(gl.createBuffer())
  2. 绑定缓冲区对象(gl.bindBuffer())
  3. 将数据写入缓冲区对象(gl.bufferData)
  4. 将缓冲区对象分配给一个 attribute 变量(gl.vertexAttribPointer())
  5. 开启 attribute 变量(gl.enableVertexAttrArray())

创建缓冲区对象

gl.createBuffer()

返回值
no-null 新创建缓冲区对象
null 创建缓冲区对象失败

gl.deleteBuffer(buffer) 删除 buffer 表示的缓冲区对象

绑定缓冲区

创建完缓冲区之后的就是将缓冲区对象绑定到webGL系统中已经存在的 target 上.

gl.bindBuffer(target, data, usage)
开辟存储空间, 向绑定在 target 上的缓冲区对象写入数据 data

参数
targetgl.ARRAY_BUFFER 或 gl.ELEMENT_ARRAY_BUFFER
data写入缓冲区对象的数据(类型化数组)
usage ↓表示程序将如何使用存储在缓存区对象的数据
gl.STATIC_DRAW只会向缓冲区对象写入一次数据, 但需要绘制很多次
gl.STREAM_DRAW只会向缓冲区对象写入一次数据, 然后绘制若干次
gl.DYNAMIC_DRAW会向缓冲区中多次写入数据, 并且绘制很多次
返回值

将缓冲区对象分配给 attribute 变量

现在我们需要将整个数组的所有值一次性地分配给一个attribute变量.

gl.vertexAttribPointer(location, size, type, normalized, stride,
offset)
将绑定到 gl.ARRAY_BUFFER 的缓冲区对象分配给由 location 指向的 attribute 变量.

参数
location指定分配 attribute 变量的存储地址
size指定缓冲区中每个顶点的分量个数(1-4). 若size < attribute 变量的分量数, 缺失分量将按规则补全, v1, v2自动设为0, v3自动设为1
type用以下类型之一的指定数据格式
gl.UNSIGNED_BYTE ——> Uint8Array
gl.SHORT ——> Int16Array
gl.UNSIGNED_SHORT ——> Uint16Array
gl.INT ——> Int32Array
gl.UNSIGNED_INT ——>Uint32Array
gl.FLOAT ——> Float32Array
normalize传入true or false, 是否将非浮点型的数据归一化到[0, 1] or [-1. 1] 区间
stride指定相邻两个顶点间的字节数, 默认为0
offset指定缓冲区对象中的偏移量(以字节为单位), 即 attribute 变量从缓冲区中的何处开始存储, 起始位置对应值为0.
返回值

开启 attribute 变量

gl.enableVertexAttrArray(location)
开启location指定的attribute变量

参数
location指定 attribute 变量的存储地址
返回值

声明:UX|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - WebGL 绘制多个点


心无旁骛似明镜