回顾

上一节我们初步体验了如何使用户与webgl程序进行交互。在最后一段绘制带颜色的点的程序中,我们使用for循环将此前保存在本地的位置及颜色信息依次加到颜色缓冲区中。当完成最后一次迭代后颜色缓冲区中的信息被一次性绘制到界面上。很显然,由于用户需要把点信息逐个的加到颜色缓冲区,这种方法的效率并不高。

WebGL提供了一种很方便的机制,即缓冲区对象(buffer object),它可以一次性地向WebGL传入多个顶点的数据。缓冲区对象是WebGL系统中的一块内存区域,我们可以一次性的向缓冲区对象中填充大量的顶点数据,然后将这些信息保存在其中,供顶点着色器使用。今后在大多数情况下我们都将使用这种方式来绘图。

目标

将若干个点保存在WebGL缓冲区对象中,然后直接一次绘制显示。

创建HTML5模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Multi Points</title>
    <style>
        body {
            margin: 0;
        }

        canvas {
            height: 100%
        }
    </style>
</head>
<body onload="loaded()">
<div>
    <canvas id="c" width="500" height="500"></canvas>
</div>
<script id="shader-vs" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    void main(){
        gl_Position = a_Position;
        gl_PointSize = 5.0;
    }

</script>
<script id="shader-fs" type="x-shader/x-fragment">
    void main(){
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }

</script>
<script src="../lib/detector.js"></script>
<script src="MultiPoints.js"></script>
</body>
</html>

本示例的模板中,顶点着色器代码与前一节别无二致,片元着色器代码相较上节进行了简化。由于不再需要根据点坐标位置来决定点的颜色,因此点的颜色被固定成了红色。

./MultiPoints.js

var gl, canvas;

function loaded() {
    canvas = document.getElementById("c");
    if (!detect()) return;
    initGL(canvas);
    initShaders();

    var n = initVertexBuffers(gl);

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

}

var g_points = [];
var g_color = [];

function initVertexBuffers(gl) {
    var vertices = new Float32Array([
        0, 0.5,
        -0.5, 0,
        0.5, 0,
        0, 0,
        0, -0.5
    ]);
    var n = 5;
    var vertexBuffer = gl.createBuffer();//创建缓冲区对象
    !vertexBuffer && console.error("Failed to create vertexBuffer");//创建缓冲区失败报错
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);//将缓冲区对象绑定到目标
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);//向缓冲区对象中写入数据

    var a_Position = gl.getAttribLocation(gl.program, "a_Position");//得到a_Position变量地址
    a_Position == -1 && console.error("Failed to get a_Position");//无法得到地址报错

    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);//将缓冲区对象分配给a_Position变量
    gl.enableVertexAttribArray(a_Position);//连接a_Position对象与分配给它的缓冲区对象

    return n;
}

function detect() {...}

function initGL(canvas) {...}

function initShaders() {...}

在其他常规初始化完成后,本例执行了一个function——initVertexBuffers。该方法中使用对缓冲区的操作替代了此前的单点操作。在主程序中,initVertexBuffers的返回值被赋予了n,它用来表明接下来我们需要画几个点。此后进行的三步操作就与我们绘制单个点的时候一模一样了:1、设置默认背景色为黑色;2、清空颜色缓冲区;3、画点,其中从第0个画到第n个。

initVertexBuffer():

缓冲区对象是WebGL系统中的一块存储区域,你可以在缓冲区对象中保存所有想要绘制的顶点数据:

具体到示例程序中,需要遵循以下五个步骤:

1):创建缓冲区对象(gl.createBuffer());

2):绑定缓冲区对象(gl.bindBuffer);

3):将数据写入缓冲区对象(gl.bufferData());

4):将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer());

5):开启attribute变量(gl.enableVertexAttribArray())。

对于其他不明白其使用方法的函数请读者自行查阅本书扉页中的[ WebGL 参考资料 ],这里仅针对较难理解的第四步(gl.vertexArrtibPointer())进行分析说明。

void WebGLRenderingContext.vertexAttribPointer(index, size, type, normalized, stride, offset)
将绑定到gl.ARRAY_BUFFER的缓冲区对象分配给由index指定的attribute变量。
参数 index 待分配attribute变量的存储位置。
size 缓冲区中每个顶点的分配数个数(1到4个)。如果size比attribute需要的变量少,剩下的则按默认值自动补全。
type 用以下类型中的一种指定数据格式:gl.UNSIGNED_BYTE、gl.SHORT、gl.UNSIGNED_SHORT、gl.INT、gl.UNSIGNED_INT、gl.FLOAT。
normalized boolean类型。表明是否将非浮点数的数据归一化到[ 0, 1 ]或[ -1, 1 ]区间。
stride 指定相邻两个顶点之间的字节数,默认为0。
offset 指定缓冲区中的偏移量(以字节为单位),即attribute变量从缓冲区中的何处开始存储。如果是从起始位置开始的,offset为0。
返回 空。

成果

https://tabrisk.github.io/webgl-getting-start/example/chapter_1/MultiPoints.html

results matching ""

    No results matching ""