alphablendingdepth-bufferwebgl2

webgl2 problem with rendering opaque and translucent triangles


I am working from a sample at https://interactivecomputergraphics.com/. My goal is to have a simple example that shows alpha blending with opaque and translucent triangles. I have 6 squares (2 triangles) each at different depth and with different colours. The nearest (yellow) and the farthest (blue) squares are opaque (alpha = 1), with the middle 4 translucent (alpha = 0.5). I enable DEPTH_TEST, set depthMask to true, and disable BLEND for individually rendering the opaque squares. Then I set depthMask to false and enable BLEND for individually rendering the translucent squares, beginning with the farthest and ending with the nearest.

I am expecting to see the yellow square always on top and fully visible, but that is not the case. I've attached a screenshot of the output when all 6 squares are opaque. I've included my code as a snippet. Any ideas?6 opaque squares, rendered as expected

/* eslint-disable require-jsdoc */
'use strict';

let gl;
let program;

let modelViewMatrix;
let projectionMatrix;
let modelViewMatrixLoc;
let projectionMatrixLoc;

const vertices = [
  vec4(-0.5, -0.5, 6.0, 1.0),
  vec4(-0.5, 0.5, 6.0, 1.0),
  vec4(0.5, 0.5, 6.0, 1.0),
  vec4(0.5, -0.5, 6.0, 1.0),
  vec4(-0.5, -0.5, 5.0, 1.0),
  vec4(-0.5, 0.5, 5.0, 1.0),
  vec4(0.5, 0.5, 5.0, 1.0),
  vec4(0.5, -0.5, 5.0, 1.0),
  vec4(-0.5, -0.5, 4.0, 1.0),
  vec4(-0.5, 0.5, 4.0, 1.0),
  vec4(0.5, 0.5, 4.0, 1.0),
  vec4(0.5, -0.5, 4.0, 1.0),
  vec4(-0.5, -0.5, 3.0, 1.0),
  vec4(-0.5, 0.5, 3.0, 1.0),
  vec4(0.5, 0.5, 3.0, 1.0),
  vec4(0.5, -0.5, 3.0, 1.0),
  vec4(-0.5, -0.5, 2.0, 1.0),
  vec4(-0.5, 0.5, 2.0, 1.0),
  vec4(0.5, 0.5, 2.0, 1.0),
  vec4(0.5, -0.5, 2.0, 1.0),
  vec4(-0.5, -0.5, 1.0, 1.0),
  vec4(-0.5, 0.5, 1.0, 1.0),
  vec4(0.5, 0.5, 1.0, 1.0),
  vec4(0.5, -0.5, 1.0, 1.0)];

const faceColors = [
  vec4(0.0, 0.0, 1.0, 1.0), // blue opaque
  vec4(0.0, 1.0, 0.0, 0.5), // green
  vec4(0.0, 1.0, 1.0, 0.5), // cyan
  vec4(1.0, 0.0, 0.0, 0.5), // red
  vec4(1.0, 0.0, 1.0, 0.5), // magenta
  vec4(1.0, 1.0, 0.0, 1.0)]; // yellow opaque

const positions = [];
const colors = [];

const near = 0;
const far = 10;
const left = -1.0;
const right = 1.0;
const bottom = -1.0;
const topp = 1.0;

const eye = vec3(0.0, 0.0, -1.0);
const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);

window.onload = function() {
  const canvas = document.getElementById('gl-canvas');

  gl = canvas.getContext('webgl2');
  if (!gl) {
    alert('WebGL 2.0 is not available');
  }

  // get the data ready for rendering
  colourSquares();

  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.clearColor(0.5, 0.5, 0.5, 1.0);
  gl.enable(gl.DEPTH_TEST);

  //
  //  Load shaders and initialize attribute buffers
  //
  program = initShaders(gl, 'vertex-shader', 'fragment-shader');
  gl.useProgram(program);

  const cBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW);
  const colorLoc = gl.getAttribLocation(program, 'aColor');
  gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(colorLoc);

  const vBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, flatten(positions), gl.STATIC_DRAW);
  const positionLoc = gl.getAttribLocation(program, 'aPosition');
  gl.vertexAttribPointer(positionLoc, 4, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(positionLoc);

  modelViewMatrixLoc = gl.getUniformLocation(program, 'uModelViewMatrix');
  projectionMatrixLoc = gl.getUniformLocation(program, 'uProjectionMatrix');

  render();
};

function render() {
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  projectionMatrix = ortho(left, right, bottom, topp, near, far);
  gl.uniformMatrix4fv(projectionMatrixLoc, false, flatten(projectionMatrix));
  // draw opaque squares, writing into depth buffer
  gl.depthMask(gl.TRUE);
  gl.disable(gl.BLEND);
  for (let i = 0; i < 6; i += 5) {
    modelViewMatrix = mult(lookAt(eye, at, up),
        mult(translate(0.5 * Math.random() - 0.25, 0.5 * Math.random() - 0.25, 0.0),
            rotateZ(360.0 * Math.random())));
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays(gl.TRIANGLES, 6 * i, 6);
  }

  // draw translucent squares, not writing into depth buffer
  gl.depthMask(gl.FALSE);
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  for (let i = 1; i < 5; i++) {
    modelViewMatrix = mult(lookAt(eye, at, up),
        mult(translate(0.5 * Math.random() - 0.25, 0.5 * Math.random() - 0.25, 0.0),
            rotateZ(360.0 * Math.random())));
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays(gl.TRIANGLES, 6 * i, 6);
  }
  setTimeout(
      function() {
        requestAnimationFrame(render);
      },
      5000);
}

function colourSquares() {
  square(1, 0, 3, 2, 0); // opaque
  square(5, 4, 7, 6, 1);
  square(9, 8, 11, 10, 2);
  square(13, 12, 15, 14, 3);
  square(17, 16, 19, 18, 4);
  square(21, 20, 23, 22, 5); // opaque
}

function square(a, b, c, d, clr) {
  // store data for the square as 2 triangles (6 vertices)
  const indices = [a, b, c, a, c, d];

  for (let i = 0; i < indices.length; ++i) {
    positions.push(vertices[indices[i]]);
    colors.push(faceColors[clr]);
  }
}
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
    #version 300 es

    in  vec4 aPosition;
    in  vec4 aColor;
    out vec4 vColor;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;

    void main()
    {
        gl_Position = uProjectionMatrix * uModelViewMatrix * aPosition;
        vColor = aColor;
    }
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
#version 300 es

precision mediump float;

in vec4 vColor;
out vec4 fColor;

void
main()
{
    fColor = vColor;
}
</script>

<script type="text/javascript" src="https://interactivecomputergraphics.com/8E/Code/Common/initShaders.js"></script>
<script type="text/javascript" src="https://interactivecomputergraphics.com/8E/Code/Common/MVnew.js"></script>

    <body>
        <canvas id="gl-canvas" width="512"" height="512">
            Your browser does not support the HTML5 canvas element
        </canvas>
    </body>
</html>


Solution

  • It appears gl.TRUE is undefined. Try using simply true, as it worked for me in this case. (same issue with gl.FALSE)