浏览器中的 webassembly gl canvas 可以使用透明背景吗?

transparent background possible for webassembly gl canvas in browser?

我正在尝试通过 C++ 中的 OpenGL 调用找到一种绘制 HTML 元素的方法,这样 canvas 后面的任何内容(背景图像,HTML text, ...) 在 GL context framebuffer 没有要绘制的不透明颜色的地方可见,或者甚至可以使用混合。

我试过在 glClearColor() 调用中将不透明度设置为零。我使用 emscripten 来编译我的 C++ 代码,当我使用它来生成模块加载器时,我注意到生成的输出中有代码使 canvas 元素的背景颜色在没有明确背景颜色时变为黑色放。我曾尝试禁用此行为,希望获得透明度,但无济于事。

我知道 Unity 的 WebGL 版本支持透明 canvases,正如所演示的那样 here。但是我不确定所说的 Unity 是否真的使用了 WebAssembly,因为我知道 JavaScript 结尾的 canvas 元素可以用来在透明背景上绘制。

这已经可以了吗?会是吗?

当然是 100% 可能,因为 WebGL 可以做到。您始终可以分叉 emscripten 库,更改几行,然后使用您的分叉。不幸的是,除非您指定如何在 emscripten 中初始化 OpenGL,否则我无法给您答案。 SDL?东格尔? GLEW?过剩?每个人都会有不同的答案。

我要做的第一件事是查看这些库的源代码。

对于 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);

它对我有用。