webgl - WebGL:为什么将透明源颜色与不透明目标颜色混合永远不会变成原始源颜色?
问题描述
在下面的示例中,我将 WebGL 画布背景颜色设置为 #444,使用 2 个不透明度为 1 的三角形绘制一个纯白色正方形,然后尝试通过多次绘制 2 个三角形来覆盖它,这些三角形完全填充画布并具有#444 的颜色和 0.1 的不透明度。
我的预期是画布颜色会在一段时间后变成#444,不透明度1.0,即画布中间的白色方块会消失。但是当背景颜色和与白色混合的覆盖颜色之间的差异在每个组件(r,g,b)中为 5 时,混合停止,因此尽管它被许多透明层完全覆盖,但您仍然可以看到正方形与背景颜色相同。我测试了许多不同的颜色,由于某种原因,每个组件的颜色差异总是 5。
你能解释一下这个现象吗?
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
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) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
let gl, colorLocation, opacityLocation, positionAttributeLocation;
function setupGL() {
const canvas = document.getElementById('canvas');
gl = canvas.getContext('webgl2', {
preserveDrawingBuffer: true
});
const vertex = `#version 300 es
in vec4 a_position;
void main() {
gl_Position = a_position;
}`;
const fragment = `#version 300 es
precision highp float;
out vec4 outColor;
uniform vec3 u_color;
uniform float u_opacity;
void main() {
outColor = vec4(u_color.xyz, u_opacity);
}`;
const triangleVertexShader = createShader(gl, gl.VERTEX_SHADER, vertex);
const triangleFragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragment);
const triangleProgram = createProgram(gl, triangleVertexShader, triangleFragmentShader);
gl.useProgram(triangleProgram);
colorLocation = gl.getUniformLocation(triangleProgram, "u_color");
opacityLocation = gl.getUniformLocation(triangleProgram, "u_opacity");
positionAttributeLocation = gl.getAttribLocation(triangleProgram, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.clearColor(0.2, 0.2, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.useProgram(triangleProgram);
gl.vertexAttribPointer(
positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
}
function main() {
setupGL();
let triangles = 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.uniform1f(opacityLocation, 1.0);
gl.uniform3f(colorLocation, 1, 1, 1);
gl.bufferData(gl.ARRAY_BUFFER, triangles, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.uniform1f(opacityLocation, 0.1);
gl.uniform3f(colorLocation, 0.2, 0.2, 0.2);
let transparentTriangles = new Float32Array(
[
-1, -1,
-1, 1,
1, 1,
1, 1,
1, -1,
-1, -1
]
);
requestAnimationFrame(drawTriangles);
function drawTriangles() {
gl.bufferData(gl.ARRAY_BUFFER, transparentTriangles, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(drawTriangles);
}
}
main();
html, body {
height: 100%;
}
#canvas {
width: 100%;
height: 100%;
}
<canvas id="canvas"></canvas>
解决方案
推荐阅读
- c - FFMPEG:使用真实时间戳信息调整编码数据包的 PTS 和 DTS
- javascript - 来自数组的 Discord Bot 随机提示,无重复
- android - 如何使用 __cxa_rethrow 调试 Android 堆栈跟踪
- python - 如何有效地转换压缩文本文件的编码?
- javascript - Pinterest 标签错误:“加载”命令被多次调用
- java - 使 JAVA MD5 哈希匹配 C# MD5 哈希
- typescript - Typescript - 确定泛型类型是否满足附加的、泛型约束的接口
- html - 如何使用 span:not() 来避免 span
- html - CSS 网格问题。停止增长侧柱
- ios - UIImagePickerController 是否必须在导航控制器中嵌入视图控制器?