WebGL gl_FragColor alpha behave differently in Chr

2019-07-24 21:38发布

Code below draws three triangles alpha value 0.5 with {premultipliedAlpha: false}.

const gl = document.querySelector('canvas').getContext('webgl', {premultipliedAlpha: false});

const canvasWidthHeight = 300;
gl.clearColor(1, 0, 0, 0.4);
// gl.clear(gl.COLOR_BUFFER_BIT);

const vertexShaderSource = `
  attribute vec2 position;
  uniform vec2 resolution;

  // All shaders have a main function
  void main() {
    vec2 glSpacePosition = (position / resolution) * 2.0 - 1.0;
    gl_Position = vec4(glSpacePosition * vec2(1, -1), 0, 1);
  }
`;

const fragmentShaderSource = `
  precision mediump float;
  uniform vec4 color;
 
  void main() {
    gl_FragColor = color;
  }
`;

function createShader(gl, type, shaderSource) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, shaderSource);
  gl.compileShader(shader);

  const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (!success) {
    console.warn(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
  }

  return shader;
}

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

function createProgram(gl, vertexShader, fragmentShader) {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  const success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!success) {
    console.log(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
  }

  return program;
}

const program = createProgram(gl, vertexShader, fragmentShader);

// We created a program on GPU, so the next step is supplying data.
const positionAttributeLocation = gl.getAttribLocation(program, 'position');
const resolutionUniformLocation = gl.getUniformLocation(program, 'resolution');
const colorUniformLocation = gl.getUniformLocation(program, 'color');

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

gl.useProgram(program);
gl.uniform2f(resolutionUniformLocation, canvasWidthHeight, canvasWidthHeight);
gl.enableVertexAttribArray(positionAttributeLocation);

gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

function drawRandomizedTriangles() {
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0, 0,
    0, canvasWidthHeight,
    canvasWidthHeight, 0
  ]), gl.STATIC_DRAW);

  gl.uniform4f(colorUniformLocation, 0, 0, 1, 0.5);

  gl.drawArrays(gl.TRIANGLES, 0, 3);

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0 + 50, 0,
    0 + 50, canvasWidthHeight,
    canvasWidthHeight + 50, 0
  ]), gl.STATIC_DRAW);

  gl.uniform4f(colorUniformLocation, 1, 0, 0, 0.5);

  gl.drawArrays(gl.TRIANGLES, 0, 3);

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0 + 100, 0,
    0 + 100, canvasWidthHeight,
    canvasWidthHeight + 100, 0
  ]), gl.STATIC_DRAW);

  gl.uniform4f(colorUniformLocation, 1, 1, 1, 0.5);

  gl.drawArrays(gl.TRIANGLES, 0, 3);
}

drawRandomizedTriangles();
body {
  display: flex;
  align-items: center;
  justify-content: center;
}

canvas {
  background: green;
}
<canvas width="300" height="300"></canvas>

Result in Chrome: enter image description here

Result in Firefox: enter image description here

The result in Firefox is what I expected.

I think it's not related to WebGL's blend since it's about blending gl_FragColor with drawing buffer instead of browser DOM, in this case, the green-background Canvas. (This thought is based on my understanding of how WebGL works)

Also: In Chrome, if the gl_FragColor.rgb is vec3(1.0, 1.0, 1.0), no matter what the gl_FragColor.a is, as long as a is not 0, the output color is pure white(when the rgb is other values, it will behave much differently). enter image description here Here is the code pen for the image above(don't want to pollute this question with too much code).

Update 1: I believe this is not a blending issue, if we enable blend by:

gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

The result will like this:enter image description here

1条回答
男人必须洒脱
2楼-- · 2019-07-24 22:25

Anser this question myself.

As @gman said in the comment area, this is a bug in chromium.
Here is the bug link(thanks to @gman again).

查看更多
登录 后发表回答