# How to draw many identical quads in WebGL efficiently?

I have recently been trying to develop a more basic one of those 'falling sand'/'powder game' style games (See here) the past few months, and after prototyping on a plain canvas, then trying PIXI.js, I decided to try and roll my own WebGL based solution so I could control the whole pipeline.

Currently I am just iterating over a 2D array representing the pixels of the canvas (500x500) then calling glDrawElements to draw a pixel sized quad at a specified location. Obviously things get pretty heavy pretty quickly in a game like this, and the frame rate drops to unusable very quickly.

I can't find examples online of drawing batches of quads in different locations with one DrawElements call in OpenGLES/WebGl, as there is no instancing support, but people seem to mention having done it. Can anyone give any pointers?

Here is my extremely simple vertex shader:

attribute vec2 position;

uniform mat3 modelViewProjectionMatrix;

void main() {
gl_Position = vec4(modelViewProjectionMatrix * vec3(position, 1.0), 1.0);
}


And here is my relevant rendering code Javascript side:

this.setSandBuffers();
material = this.materials.sand;
this.gl.vertexAttribPointer(this.positionAttribute, 2, this.gl.FLOAT, false, 0, 0);
this.gl.uniform4fv(this.uColor, material.uColor);

for (var x = 0; x < this.grid.length; x++) {
for (var y = 0; y < this.grid[x].length; y++) {
var cell = this.grid[x][y];

switch(cell) {
case 0:
break;
case 1:

this.mvTranslate(x, y);

mvpMatrix = matrixMultiply(this.modelViewMatrix, this.projectionMatrix);

this.gl.uniformMatrix3fv(this.uModelViewProjectionMatrix, false, mvpMatrix);

this.gl.drawElements(this.gl.TRIANGLE_STRIP, 4, this.gl.UNSIGNED_SHORT, 0);

break;
default:
break;
}
}
}


Any other relevant code is here.

Thanks

An individual draw call per quad is not a good idea.

Try putting all the quads into a Float32Array, and issuing one draw call. Something like this, assuming the vertex data only contains 2D positions:

var vertices = new Float32Array(500 * 500 * 2 * 6);
var count = 0;

for (var x = 0; x < this.grid.length; x++)
{
for (var y = 0; y < this.grid[x].length; y++)
{
var cell = this.grid[x][y];

switch(cell)
{
case 1:
var offset = count * 2 * 6;
vertices[offset + 0] = x;
vertices[offset + 1] = y;
vertices[offset + 2] = x + 1;
vertices[offset + 3] = y;
vertices[offset + 4] = x;
vertices[offset + 5] = y + 1;

vertices[offset + 6] = x;
vertices[offset + 7] = y + 1;
vertices[offset + 8] = x + 1;
vertices[offset + 9] = y;
vertices[offset + 10] = x + 1;
vertices[offset + 11] = y + 1;

count++;
break;

default:
break;
}
}
}

gl.enableVertexAttribArray(position);
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 16, 0);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, count * 6);

• Implemented a tweaked form of this and it works much better, thanks! – Milo Mordaunt Jan 12 '14 at 19:25