WebGL gl_FragColor alpha 在 Chrome 中与 Firefox 的行为不同
WebGL gl_FragColor alpha behave differently in Chrome with Firefox
下面的代码用 {premultipliedAlpha: false}
.
绘制了三个三角形 alpha
值为 0.5
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>
Chrome结果:
Firefox 中的结果:
Firefox 中的结果符合我的预期。
我认为它与 WebGL 的混合无关,因为它是关于将 gl_FragColor
与绘图缓冲区而不是浏览器 DOM 混合,在本例中为绿色背景 Canvas。
(这个想法是基于我对 WebGL 工作原理的理解)
另外:在Chrome中,如果gl_FragColor.rgb
是vec3(1.0, 1.0, 1.0)
,不管gl_FragColor.a
是什么,只要a
不是0
,输出颜色为纯白色(当 rgb
为其他值时,它的表现会大不相同)。
这是上图的 code pen(不想用太多代码污染这个问题)。
更新 1:我相信这不是混合问题,如果我们通过以下方式启用混合:
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
结果会是这样:
自己回答这个问题。
正如@gman在评论区所说,这是chromium的一个bug
这是bug link(再次感谢@gman)。
下面的代码用 {premultipliedAlpha: false}
.
alpha
值为 0.5
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>
Chrome结果:
Firefox 中的结果:
Firefox 中的结果符合我的预期。
我认为它与 WebGL 的混合无关,因为它是关于将 gl_FragColor
与绘图缓冲区而不是浏览器 DOM 混合,在本例中为绿色背景 Canvas。
(这个想法是基于我对 WebGL 工作原理的理解)
另外:在Chrome中,如果gl_FragColor.rgb
是vec3(1.0, 1.0, 1.0)
,不管gl_FragColor.a
是什么,只要a
不是0
,输出颜色为纯白色(当 rgb
为其他值时,它的表现会大不相同)。
更新 1:我相信这不是混合问题,如果我们通过以下方式启用混合:
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
结果会是这样:
自己回答这个问题。
正如@gman在评论区所说,这是chromium的一个bug
这是bug link(再次感谢@gman)。