'WebGL mix instanced sprite rendering

I want to render some instanced sprites using drawArraysInstancedANGLE. The problem is that when i set vertexAttribDivisorANGLE for the buffer to be instanced, it clears the whole screen, erasing anything i drawn earlier. I based this example on https://stackoverflow.com/a/56066386/1227852

Example with the vertexAttribDivisorANGLE issue (only draws the instanced boxes):

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
  alert('need ANGLE_instanced_arrays');
}


// create a simple background shader

const backgroundVs = `
  attribute vec2 position;
 
  void main() {
    gl_Position = vec4(position, 0.0, 1.0);
  }
`;

const backgroundFs = `
precision mediump float;

uniform vec2 resolution;

void main() {
  vec2 uv = gl_FragCoord.xy/resolution.xy;
  vec3 color = uv.xyx;
  gl_FragColor = vec4(color, 1.0);
  gl_FragColor = vec4(1.0,0.0,0.0,1.0);
  gl_FragColor = vec4(color,1.0);
}
`;


const backgroundProgramInfo = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundProgram = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundPositionLoc = gl.getAttribLocation(backgroundProgram, 'position');
const backgroundResolutionLoc = gl.getUniformLocation(backgroundProgram, 'resolution');

const backgroundQuad = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  1, 1,   // 1 +-----+ 2
  -1, 1,  // |       |
  1, -1,  // |       |
  1, -1,  // |       |
  -1, 1,  // |       |
  -1, -1, // 3 +-----+ 0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(backgroundPositionLoc);
gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);


//Create an instanced point renderer (based on: )

const vs = `
  attribute vec4 position;       // center point
  attribute vec2 cornerPosition; // the corners (-0.5 to 0.5)
  
  uniform vec2 resolution;
  uniform mat4 matrix;
  
  varying vec3 pointCoord;  // only if you need gl_PointCoord substitute
  
  void main() {
    // do the normal thing (can mult by matrix or whatever here
    gl_Position = matrix * position; 

    float pointSize = 20.0 / gl_Position.w;
    
    // -- point emulation
    
    gl_Position.xy += cornerPosition * (pointSize * 2.0 - 1.0) / 
                      resolution * gl_Position.w;
    
    // only if you need gl_PointCoord substitute
    pointCoord = vec3(cornerPosition * 0.5, gl_Position.z);
  }
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;

const programInfo = twgl.createProgram(gl, [vs, fs]);

const program = twgl.createProgram(gl, [vs, fs]);
const positionLoc = gl.getAttribLocation(program, 'position');
const cornerPositionLoc = gl.getAttribLocation(program, 'cornerPosition');
const resolutionLoc = gl.getUniformLocation(program, 'resolution');
const matrixLoc = gl.getUniformLocation(program, 'matrix');

const bufSprites = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1.001, -1.001,
   1.001, -1.001,
  -1.001,  1.001,
   1.001,  1.001,
   0,      0,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);

const bufCorners = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -0.5, -0.5,
   0.5, -0.5,
  -0.5,  0.5,
    
  -0.5,  0.5,
   0.5, -0.5,
   0.5,  0.5,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(cornerPositionLoc);
gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);


function render(ms) {
  const secs = ms * 0.001;

  gl.useProgram(backgroundProgram);

  gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
  gl.enableVertexAttribArray(backgroundPositionLoc);
  gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(backgroundResolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.drawArrays(gl.TRIANGLES, 0, 6);


  const mat = m4.perspective(
      60 * Math.PI / 180,
      gl.canvas.clientWidth / gl.canvas.clientHeight,
      0.1,
      100);
  m4.translate(mat, [0, 0, -2.11 + Math.sin(secs)], mat);
  

  gl.useProgram(program);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
  ext.vertexAttribDivisorANGLE(positionLoc, 1);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
  gl.enableVertexAttribArray(cornerPositionLoc);
  gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.uniformMatrix4fv(matrixLoc, false, mat);
  
  // 6 verts per point
  ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 5);
  
  requestAnimationFrame(render);
}
render(0);
<html>

    <head>
        <style>canvas { border: 1px solid black; width: 100%; height: 100%;}</style>
        <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    </head>

    <body>
        <canvas></canvas>
    </body>
    
</html>

Now when i disable the ext.vertexAttribDivisorANGLE(positionLoc, 1); call, the background renders like expected and the boxes are drawn over the background, but obviously the mesh is incorrect since the instancing / divisor is not set correctly:

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
  alert('need ANGLE_instanced_arrays');
}


// create a simple background shader

const backgroundVs = `
  attribute vec2 position;
 
  void main() {
    gl_Position = vec4(position, 0.0, 1.0);
  }
`;

const backgroundFs = `
precision mediump float;

uniform vec2 resolution;

void main() {
  vec2 uv = gl_FragCoord.xy/resolution.xy;
  vec3 color = uv.xyx;
  gl_FragColor = vec4(color, 1.0);
  gl_FragColor = vec4(1.0,0.0,0.0,1.0);
  gl_FragColor = vec4(color,1.0);
}
`;


const backgroundProgramInfo = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundProgram = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundPositionLoc = gl.getAttribLocation(backgroundProgram, 'position');
const backgroundResolutionLoc = gl.getUniformLocation(backgroundProgram, 'resolution');

const backgroundQuad = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  1, 1,   // 1 +-----+ 2
  -1, 1,  // |       |
  1, -1,  // |       |
  1, -1,  // |       |
  -1, 1,  // |       |
  -1, -1, // 3 +-----+ 0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(backgroundPositionLoc);
gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);


//Create an instanced point renderer (based on: )

const vs = `
  attribute vec4 position;       // center point
  attribute vec2 cornerPosition; // the corners (-0.5 to 0.5)
  
  uniform vec2 resolution;
  uniform mat4 matrix;
  
  varying vec3 pointCoord;  // only if you need gl_PointCoord substitute
  
  void main() {
    // do the normal thing (can mult by matrix or whatever here
    gl_Position = matrix * position; 

    float pointSize = 20.0 / gl_Position.w;
    
    // -- point emulation
    
    gl_Position.xy += cornerPosition * (pointSize * 2.0 - 1.0) / 
                      resolution * gl_Position.w;
    
    // only if you need gl_PointCoord substitute
    pointCoord = vec3(cornerPosition * 0.5, gl_Position.z);
  }
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;

const programInfo = twgl.createProgram(gl, [vs, fs]);

const program = twgl.createProgram(gl, [vs, fs]);
const positionLoc = gl.getAttribLocation(program, 'position');
const cornerPositionLoc = gl.getAttribLocation(program, 'cornerPosition');
const resolutionLoc = gl.getUniformLocation(program, 'resolution');
const matrixLoc = gl.getUniformLocation(program, 'matrix');

const bufSprites = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1.001, -1.001,
   1.001, -1.001,
  -1.001,  1.001,
   1.001,  1.001,
   0,      0,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);

const bufCorners = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -0.5, -0.5,
   0.5, -0.5,
  -0.5,  0.5,
    
  -0.5,  0.5,
   0.5, -0.5,
   0.5,  0.5,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(cornerPositionLoc);
gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);


function render(ms) {
  const secs = ms * 0.001;

  gl.useProgram(backgroundProgram);

  gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
  gl.enableVertexAttribArray(backgroundPositionLoc);
  gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(backgroundResolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.drawArrays(gl.TRIANGLES, 0, 6);


  const mat = m4.perspective(
      60 * Math.PI / 180,
      gl.canvas.clientWidth / gl.canvas.clientHeight,
      0.1,
      100);
  m4.translate(mat, [0, 0, -2.11 + Math.sin(secs)], mat);
  

  gl.useProgram(program);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
  //ext.vertexAttribDivisorANGLE(positionLoc, 1);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
  gl.enableVertexAttribArray(cornerPositionLoc);
  gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.uniformMatrix4fv(matrixLoc, false, mat);
  
  // 6 verts per point
  ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 5);
  
  requestAnimationFrame(render);
}
render(0);
<html>

    <head>
        <style>canvas { border: 1px solid black; width: 100%; height: 100%;}</style>
        <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    </head>

    <body>
        <canvas></canvas>
    </body>
    
</html>

How can i render the instanced boxes correctly over the background without the background being erased?

edit: removed some unnecessary commented lines

edit 2: as pointed out by user253751, i needed to turn off the divisor using ext.vertexAttribDivisorANGLE(positionLoc, 0); right after the drawArraysInstancedANGLE call

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
  alert('need ANGLE_instanced_arrays');
}


// create a simple background shader

const backgroundVs = `
  attribute vec2 position;
 
  void main() {
    gl_Position = vec4(position, 0.0, 1.0);
  }
`;

const backgroundFs = `
precision mediump float;

uniform vec2 resolution;

void main() {
  vec2 uv = gl_FragCoord.xy/resolution.xy;
  vec3 color = uv.xyx;
  gl_FragColor = vec4(color, 1.0);
  gl_FragColor = vec4(1.0,0.0,0.0,1.0);
  gl_FragColor = vec4(color,1.0);
}
`;


const backgroundProgramInfo = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundProgram = twgl.createProgram(gl, [backgroundVs, backgroundFs]);
const backgroundPositionLoc = gl.getAttribLocation(backgroundProgram, 'position');
const backgroundResolutionLoc = gl.getUniformLocation(backgroundProgram, 'resolution');

const backgroundQuad = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  1, 1,   // 1 +-----+ 2
  -1, 1,  // |       |
  1, -1,  // |       |
  1, -1,  // |       |
  -1, 1,  // |       |
  -1, -1, // 3 +-----+ 0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(backgroundPositionLoc);
gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);


//Create an instanced point renderer (based on: )

const vs = `
  attribute vec4 position;       // center point
  attribute vec2 cornerPosition; // the corners (-0.5 to 0.5)
  
  uniform vec2 resolution;
  uniform mat4 matrix;
  
  varying vec3 pointCoord;  // only if you need gl_PointCoord substitute
  
  void main() {
    // do the normal thing (can mult by matrix or whatever here
    gl_Position = matrix * position; 

    float pointSize = 20.0 / gl_Position.w;
    
    // -- point emulation
    
    gl_Position.xy += cornerPosition * (pointSize * 2.0 - 1.0) / 
                      resolution * gl_Position.w;
    
    // only if you need gl_PointCoord substitute
    pointCoord = vec3(cornerPosition * 0.5, gl_Position.z);
  }
`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;

const programInfo = twgl.createProgram(gl, [vs, fs]);

const program = twgl.createProgram(gl, [vs, fs]);
const positionLoc = gl.getAttribLocation(program, 'position');
const cornerPositionLoc = gl.getAttribLocation(program, 'cornerPosition');
const resolutionLoc = gl.getUniformLocation(program, 'resolution');
const matrixLoc = gl.getUniformLocation(program, 'matrix');

const bufSprites = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1.001, -1.001,
   1.001, -1.001,
  -1.001,  1.001,
   1.001,  1.001,
   0,      0,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);

const bufCorners = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -0.5, -0.5,
   0.5, -0.5,
  -0.5,  0.5,
    
  -0.5,  0.5,
   0.5, -0.5,
   0.5,  0.5,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(cornerPositionLoc);
gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);


function render(ms) {
  const secs = ms * 0.001;

  gl.useProgram(backgroundProgram);

  gl.bindBuffer(gl.ARRAY_BUFFER, backgroundQuad);
  gl.enableVertexAttribArray(backgroundPositionLoc);
  gl.vertexAttribPointer(backgroundPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(backgroundResolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.drawArrays(gl.TRIANGLES, 0, 6);


  const mat = m4.perspective(
      60 * Math.PI / 180,
      gl.canvas.clientWidth / gl.canvas.clientHeight,
      0.1,
      100);
  m4.translate(mat, [0, 0, -2.11 + Math.sin(secs)], mat);
  

  gl.useProgram(program);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufSprites);
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
  ext.vertexAttribDivisorANGLE(positionLoc, 1);

  gl.bindBuffer(gl.ARRAY_BUFFER, bufCorners);
  gl.enableVertexAttribArray(cornerPositionLoc);
  gl.vertexAttribPointer(cornerPositionLoc, 2, gl.FLOAT, false, 0, 0);

  gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
  gl.uniformMatrix4fv(matrixLoc, false, mat);
  
  // 6 verts per point
  ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 5);
  ext.vertexAttribDivisorANGLE(positionLoc, 0);
 
  requestAnimationFrame(render);
}
render(0);
<html>

    <head>
        <style>canvas { border: 1px solid black; width: 100%; height: 100%;}</style>
        <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
    </head>

    <body>
        <canvas></canvas>
    </body>
    
</html>


Solution 1:[1]

You need to turn the divisor off by setting it to 0 before drawing the background. Otherwise, it is used for the background as well, and the background is drawn incorrectly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user253751