1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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);
\$\endgroup\$
1
  • \$\begingroup\$ Implemented a tweaked form of this and it works much better, thanks! \$\endgroup\$ Jan 12 '14 at 19:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .