我使用完全相同的 C++ 代码渲染相同的场景,一次使用 Windows 上的本机 OpenGL,一次使用 Emscripten 渲染 WebGL。场景中的所有内容看起来都完全相同,除非我使用 alpha != 1.0 渲染某些内容。区别如下:
蓝色立方体的颜色是
(0.0, 0.0, 1.0, 0.5)
(0.5, 0.5, 1.0, 0.5)
我使用的混合功能是标准的:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
WebGL 中的 alpha 是否有某种差异?什么可能导致这种情况发生?
您是否将画布设置为非预乘?
gl = someCanvas.getContext("webgl", { premultipliedAlpha: false });
WebGL 的默认值为 true。大多数 OpenGL 应用程序的默认值是 false
WebGL 与页面的其余部分合成。至少是画布或其内部的任何内容(文档正文)的背景颜色。
要查看这是否是问题所在,请尝试将画布的背景颜色设置为紫色或会突出的颜色
<canvas ... style="background-color: #F0F;"></canvas>
或者在CSS中
canvas { background-color: #F0F; }
OpenGL 应用程序很少在任何东西上进行合成,而 WebGL 应用程序总是有效地进行合成。
一些解决方案
关闭阿尔法
如果您的目的地不需要 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);
如果需要,请不要忘记将颜色遮罩设置回全部 true 稍后清除颜色缓冲区
将画布的背景颜色设置为黑色
canvas { background-color: #000; }
如果可能的话我会选择关闭 Alpha。如果将 alpha 设置为关闭,则浏览器可能会在将画布绘制到浏览器中时关闭混合。根据 GPU 的不同,速度可能会提高 10-20% 或更多。不能保证任何浏览器都会进行这种优化,只是可以做到这一点,而使用其他两种解决方案则不可能或至少不太可能
我在使用 Emscripten、SDL3 和 OpenGL ES 2.0 时也遇到了同样的问题。比较 WASM 和 EXE 构建(围绕主角的白色曲线):
您应该像这样禁用
alpha
和 premultipliedAlpha
:
#ifdef __EMSCRIPTEN__
#include <emscripten/html5.h>
#include <SDL3/SDL_opengles2.h>
#else
#include <glad/glad.h>
#endif // __EMSCRIPTEN__
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
// ...
// Paste the following code after SDL_CreateWindow and before SDL_GL_CreateContext
#ifdef __EMSCRIPTEN__
EmscriptenWebGLContextAttributes attrs;
emscripten_webgl_init_context_attributes(&attrs);
attrs.alpha = EM_FALSE; // Disable alpha blending
attrs.premultipliedAlpha = EM_FALSE; // Disable premultiplied alpha
attrs.depth = EM_TRUE; // Enable depth testing
attrs.stencil = EM_FALSE; // Disable stencil testing
attrs.antialias = EM_FALSE; // Disable anti-aliasing
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attrs);
#endif // __EMSCRIPTEN__
// ...
}
问题解决了: