Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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

share|improve this question

1 Answer 1

up vote 1 down vote accepted

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);
share|improve this answer
    
Implemented a tweaked form of this and it works much better, thanks! –  Milo Mordaunt Jan 12 at 19:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.