OpenGL 和 WebGL 之间的 Alpha 渲染差异

Alpha rendering difference between OpenGL and WebGL

我正在使用完全相同的 C++ 代码渲染相同的场景,一次是在 windows 上使用原生 OpenGL,一次是使用 Emscripten 到 WebGL。场景中的一切看起来都完全一样,除了当我用 alpha != 1.0 渲染某些东西时。差异如下所示:

蓝色立方体的颜色是(0.0, 0.0, 1.0, 0.5)
用于渲染立方体的着色器除了绘制颜色外什么都不做。
右边是它在 OpenGL 中的样子,也是预期的结果,只是蓝色,半透明。左边是使用 Emscripten+WebGL 时的样子。看起来渲染的颜色实际上是 (0.5, 0.5, 1.0, 0.5)

我使用的混合函数是标准的:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

WebGL 中的 alpha 有什么不同吗?什么可能导致这种情况发生?

您是否将 canvas 设置为非预乘?

gl = someCanvas.getContext("webgl", { premultipliedAlpha: false });

WebGL 的默认值为真。大多数 OpenGL 应用程序的默认值为 false

在此之上,WebGL 与页面的其余部分合成在一起。至少是 canvas 或它里面的任何内容(文档正文)的背景颜色。

要查看这是否是问题所在,请尝试将 canvas 的背景颜色设置为紫色或其他会突出的颜色

<canvas ... style="background-color: #F0F;"></canvas>

或 css

canvas { background-color: #F0F; }

OpenGL 应用很少在任何地方合成,因为 WebGL 应用总是有效地合成。

一些解决方案

  • 关闭 alpha

    如果您的目的地不需要 alpha,您可以将其关闭

    gl = someCanvas.getContext("webgl", { alpha: false });
    

    现在 alpha 实际上是 1

  • 在一帧结束时将 alpha 设置为 1

    // clear only the alpha channel to 1
    gl.clearColor(1, 1, 1, 1);
    gl.colorMask(false, false, false, true);
    gl.clear(gl.COLOR_BUFFER_BIT);
    

    如果需要,请不要忘记将颜色遮罩设置回 all tr​​ue 稍后清除颜色缓冲区

  • 将 canvas 的背景颜色设置为黑色

    canvas { background-color: #000; }
    

如果可能的话,我会选择关闭 alpha。将 alpha 设置为关闭的原因是浏览器可以在将 canvas 绘制到浏览器中时关闭混合。根据 GPU,速度可能会提高 10-20% 或更多。不能保证任何浏览器都会进行这种优化,只是有可能做到,而对于其他 2 种解决方案,这是不可能的,或者至少不太可能