浏览器中的 webassembly gl 画布可以使用透明背景吗?
Posted
技术标签:
【中文标题】浏览器中的 webassembly gl 画布可以使用透明背景吗?【英文标题】:transparent background possible for webassembly gl canvas in browser? 【发布时间】:2019-11-28 13:05:04 【问题描述】:我正在尝试找到一种方法,通过 C++ 中的 OpenGL 调用来绘制 html 元素,这样画布后面的任何内容(背景图像、HTML 文本等)在 GL 的地方都是可见的上下文帧缓冲区没有要绘制的不透明颜色,甚至可能具有使用混合的能力。
我尝试在 glClearColor() 调用中将不透明度设置为零。我使用 emscripten 编译我的 C++ 代码,当我使用它生成模块加载器时,我注意到生成的输出中有代码在没有明确设置背景颜色时使画布元素的背景颜色变为黑色。为了获得透明度,我尝试禁用此行为,但无济于事。
我知道 Unity 的 WebGL 版本支持透明画布,如 here 所示。但我不确定其中所说的 Unity 是否真的使用了 WebAssembly,因为我确实知道画布元素的 javascript 端可用于在透明背景上绘制。
这已经可能了吗?会有吗?
【问题讨论】:
这并不是真正的 webassembly 问题,因为它生成的代码只编译为 webassembly。所以你应该更准确地标记它。 我认为这是 webassembly 特有的问题,因为当 webassembly 程序创建链接到它的 webgl 上下文时,提供 canvas 元素的主机会显示某种行为(将画布涂成黑色)。跨度> 从 Web 程序集到画布没有直接绑定,有一些胶水 javascript 代码。所以问题是由胶水代码、编译为 webassembly 的代码或一些将背景设置为纯色的 html 或 css 造成的。你可以找到类似的,但例如在这里 github.com/processing/p5.js/issues/2766 他们说这也有助于为 gl 上下文启用 alpha。 【参考方案1】:当然这是 100% 可能的,因为 WebGL 可以做到。您可以随时 fork emscripten 库,更改几行代码,然后使用您的 fork。不幸的是,除非您指定如何在 emscripten 中初始化 OpenGL,否则我无法给您答案。 SDL? EGL?发光?过剩?每个人都会有不同的答案。
我要做的第一件事就是查看这些库的源代码。
对于 SDL,我们看到 this
$SDL:
defaults:
width: 320,
height: 200,
// If true, SDL_LockSurface will copy the contents of each surface back to the Emscripten HEAP so that C code can access it. If false,
// the surface contents are captured only back to JS code.
copyOnLock: true,
// If true, SDL_LockSurface will discard the contents of each surface when SDL_LockSurface() is called. This greatly improves performance
// of SDL_LockSurface(). If discardOnLock is true, copyOnLock is ignored.
discardOnLock: false,
// If true, emulate compatibility with desktop SDL by ignoring alpha on the screen frontbuffer canvas. Setting this to false will improve
// performance considerably and enables alpha-blending on the frontbuffer, so be sure to properly write 0xFF alpha for opaque pixels
// if you set this to false!
opaqueFrontBuffer: true
,
和this
var webGLContextAttributes =
antialias: ((SDL.glAttributes[13 /*SDL_GL_MULTISAMPLEBUFFERS*/] != 0) && (SDL.glAttributes[14 /*SDL_GL_MULTISAMPLESAMPLES*/] > 1)),
depth: (SDL.glAttributes[6 /*SDL_GL_DEPTH_SIZE*/] > 0),
stencil: (SDL.glAttributes[7 /*SDL_GL_STENCIL_SIZE*/] > 0),
alpha: (SDL.glAttributes[3 /*SDL_GL_ALPHA_SIZE*/] > 0)
;
对于 EGL,有 this
var LibraryEGL =
$EGL__deps: ['$Browser'],
$EGL:
// This variable tracks the success status of the most recently invoked EGL function call.
errorCode: 0x3000 /* EGL_SUCCESS */,
defaultDisplayInitialized: false,
currentContext: 0 /* EGL_NO_CONTEXT */,
currentReadSurface: 0 /* EGL_NO_SURFACE */,
currentDrawSurface: 0 /* EGL_NO_SURFACE */,
alpha: false,
对于 GLUT,有 this
glutCreateWindow: function(name)
var contextAttributes =
antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0),
depth: ((GLUT.initDisplayMode & 0x0010 /*GLUT_DEPTH*/) != 0),
stencil: ((GLUT.initDisplayMode & 0x0020 /*GLUT_STENCIL*/) != 0),
alpha: ((GLUT.initDisplayMode & 0x0008 /*GLUT_ALPHA*/) != 0)
;
似乎它们可能会导致答案?
否则,如果您懒得通读源代码,那么您可以强制它。在任何其他脚本之前将此代码添加到 html 文件的顶部
<script>
(function()
if (typeof HTMLCanvasElement !== "undefined")
wrapGetContext(HTMLCanvasElement);
if (typeof OffscreenCanvas !== "undefined")
wrapGetContext(OffscreenCanvas);
function wrapGetContext(ContextClass)
const isWebGL = /webgl/i;
ContextClass.prototype.getContext = function(origFn)
return function(type, attributes)
if (isWebGL.test(type))
attributes = Object.assign(, attributes || , alpha: true);
return origFn.call(this, type, attributes);
;
(ContextClass.prototype.getContext);
());
</script>
我用this sample 测试过,更改了这一行
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
到这里
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
它对我有用。
【讨论】:
我目前正在使用 SDL。以上是关于浏览器中的 webassembly gl 画布可以使用透明背景吗?的主要内容,如果未能解决你的问题,请参考以下文章
Blazor WebAssembly + Grpc Web = 未来?
Blazor WebAssembly + Grpc Web=未来?