0

I want to make a batched renderer, where I put multiple mesh information (vertices, uvs, indices) into a single buffer and draw them in one gl.drawElements call.

These meshes can change position and scale, these transformations affect the vertex data, thus updating the vertices buffer. That means extra gl.bindBuffer call.

I couldn't make a working version, but before anything else I have this performance problem with gl.bindBuffer, it is called on each render and takes a lot of time, in this function:

function renderFunction() {
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(array), drawType);

    this.renderBatched(...);
}


this.renderBatched = (drawInfo, uniformArgs, indices) => {
  const cookUniforms = Object.keys(drawInfo.uniforms).map(key => {
    let setter = drawInfo.uniforms[key];
    let args = uniformArgs[key];
    return () => {
      if (!args) {
        throw new Error("undefined uniform " + key);
      }
      setter(...args);
    };
  });

  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);

  let {
    program,
    uniforms,
    textureInfos,
    bufferInfos
  } = drawInfo;

  gl.useProgram(program);

  bufferInfos.forEach(({
    buffer,
    size,
    index
  }) => {
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

    gl.vertexAttribPointer(index,
                           size,
                           gl.FLOAT,
                           false,
                           0,
                           0);
    gl.enableVertexAttribArray(index);

  });

  let indexBuffer = gl.createBuffer();

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

  // https://stackoverflow.com/questions/38948908/vbo-and-ebo-state-in-webgl
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
                new Uint16Array(indices),
                gl.STATIC_DRAW);


  textureInfos.forEach(({ glTexture, index }) => {
    gl.uniform1i(index, 0);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, glTexture);
  });


  cookUniforms.forEach(_ => _());

  let numElements = indices.length;

  gl.drawElements(gl.TRIANGLES, numElements, gl.UNSIGNED_SHORT, 0);
};

So I need to eliminate gl.bufferData calls instead of each render, but what do I do when the buffer data changes when the meshes transform.

I look up PIXI source but I don't understand anything.

I am not concerned about textures at the moment, I want to draw lots of moving quads on the screen with no performance hit.

eguneys
  • 6,028
  • 7
  • 31
  • 63
  • "I want to draw lots of moving quads on the screen with no performance hit."? The more things you draw the more performance is required. There is no magic that will make that not true. There are optimizations, but "no performance hit" is impossible. One perf boost would be using Uint16Array and Float32Array directly instead of converting every frame as the code is doing above. Also what does this have to do with pixi.js? None of the code above appears to have any relatoinship to pixi.js. – gman Mar 22 '20 at 03:52
  • you might be interested in [instanced drawing](https://webglfundamentals.org/webgl/lessons/webgl-instanced-drawing.html) and [other techniques](https://stackoverflow.com/questions/54701606/how-to-do-batching-without-ubos/54720138#54720138) and also [this](https://webglsamples.org/google-io/2011/index.html) – gman Mar 22 '20 at 04:02
  • There is a simple js library for batch rendering sprites: https://github.com/kutuluk/js13k-2d/blob/master/src/renderer.js – eguneys Mar 22 '20 at 23:18

0 Answers0