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>
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).
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);
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).