回顾
上一节我们初步体验了如何使用户与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