As described in Chapter 2, Rendering, we can implement vertex array objects in WebGL 1 by using the OES_vertex_array_object extension. That being said, they are available by default in WebGL 2. This is an important feature that should always be used, since it significantly reduces rendering times. When not using vertex array objects, all attributes data is in a global WebGL state, which means that calling functions such as gl.vertexAttribPointer, gl.enableVertexAttribArray, and gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer) manipulates the global state. This leads to performance loss, because before any draw call, we would need to set up all vertex attributes and set the ELEMENT_ARRAY_BUFFER where indexed data is being used. On the other hand, with vertex array objects, we would set up all attributes during our application's initialization and simply bind the data during rendering, yielding much better performance.
This is very similar to the IDirect3DVertexDeclaration9/ID3D11InputLayout interfaces in DirectX land.
WebGL 1 with Extension | WebGL 2 |
---|---|
createVertexArrayOES | createVertexArray |
deleteVertexArrayOES | deleteVertexArray |
isVertexArrayOES | isVertexArray |
bindVertexArrayOES |
bindVertexArray |
An example of this is as follows:
// Create a VAO instance
var vertexArray = gl.createVertexArray();
// Bind the VAO
gl.bindVertexArray(vertexArray);
// Set vertex array states
// Set with GLSL layout qualifier
const vertexPositionLocation = 0;
// Enable the attribute
gl.enableVertexAttribArray(vertexPositionLocation);
// Bind Buffer
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
// ...
// Configure instructions for VAO
gl.vertexAttribPointer(vertexPositionLocation, 2, gl.FLOAT, false, 0, 0);
// Clean
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// ...
// Render
gl.bindVertexArray(vertexArray);
gl.drawArrays(gl.TRIANGLES, 0, 6);