Search code examples
javascriptwebgl

After drawing instanced arrays, what is the procedure for executing a regular draw operation?


I wrote some WebGL2 code to render a few thousand circles using drawArraysInstanced. I'm using code from https://webgl2fundamentals.org/webgl/lessons/webgl-instanced-drawing.html.

I also have a fullscreen quad to display a more appealing background than black. Both work independently, but rendering the instanced array of circles disrupts the background rendering.

I suspect I should unbind or unset something after rendering the circles, but I can't tell what. The problem is that the webgl2 fundamentals example doesn't specify what has to happen every frame and what has to happen once, and it doesn't attempt to render anything but the instanced arrays.

How can I clean the webgl2 state after rendering the instanced arrays so that regular rendering works again?

https://jsfiddle.net/g2xkoc56/

gl.useProgram(shader);
    gl.uniform4fv(colorUniform, color);
    gl.uniformMatrix4fv(viewProjectionMatrixUniform, false, viewProjectionMatrix);

    bindIndexBuffer(gl, indexBuffer);

    // upload the new matrix data
    for (let i = 0; i < count; ++i) {
      const offset = i * 16;
      mat4.fromTranslation(matrixData.subarray(offset, offset + 16), positions[i]);
    }
    gl.bindBuffer(gl.ARRAY_BUFFER, matrixBuffer);
    gl.bufferSubData(gl.ARRAY_BUFFER, 0, matrixData);

    const bytesPerMatrix = 4 * 16;
    for (let i = 0; i < 4; ++i) {
      const loc = matrixAttribute + i;
      gl.enableVertexAttribArray(loc);
      // note the stride and offset
      const offset = i * 16;  // 4 floats per row, 4 bytes per float
      gl.vertexAttribPointer(
        loc,              // location
        4,                // size (num values to pull from buffer per iteration)
        gl.FLOAT,    // type of data in buffer
        false,            // normalize
        bytesPerMatrix,   // stride, num bytes to advance to get to next set of values
        offset,           // offset in buffer
      );
      // this line says this attribute only changes for each 1 instance
      gl.vertexAttribDivisor(loc, 1);
    }

    bindVertexBuffer(gl, vertexPositionAttribute, vertexBuffer, 3);
    bindIndexBuffer(gl, indexBuffer);
    gl.drawArraysInstanced(
      gl.TRIANGLE_FAN, // GL Fan, strip, etc.
      0,       // offset
      sides+2, // num vertices per instance
      count,   // num instances
    );
    unbindIndexBuffer(gl);
    unbindVertexBuffer(gl, vertexPositionAttribute);
    for (let i = 0; i < 4; ++i) {
      gl.disableVertexAttribArray(matrixAttribute + i);
    }

Screenshots: before particles run, background is visible after particles render, background is still visible Rerendering background doesn't work:


Solution

  • I wasn't clearing the vertex attrib divisor for the instanced matrices properly after rendering the instanced particles, which was preventing the background from rendering next frame. (Though some people didn't have an issue with the same code, so maybe it was something else.)

    After rendering the particles, before the break between frames:

    for (let i = 0; i < 4; ++i) {
      gl.vertexAttribDivisor(matrixAttribute + i, 0);
    }