How to Make Webgl Canvas Transparent

How to make WebGL canvas transparent

WebGL supports alpha transparency by default, but you have to use it. Most basically, make sure you have set the clear color to transparent, gl.clearColor(0, 0, 0, 0), before your gl.clear operation.

If you want to have semi-transparent objects drawn, that gets into blending operations and sorted drawing, but it looks like you just want the un-drawn area to be transparent, which the above is sufficient for.

make webgl canvas transparent

gl_FragColor = texture2D(uTexture, vUv);

This line is states that fragColor witch is vec4 gonna be colored by sampled texture.

Basically you can think about vec4 in this case as an RGBA vector, so if you do something like:

gl_FragColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);

at this pixel color gonna be black but not transparent

gl_FragColor = vec4(1.0f, 1.0f, 1.0f, 0.0f);

Would be a white but transparent pixel

So by doing this:

 gl_FragColor = dissipation * texture2D(uSource, coord);
gl_FragColor.a = 1.0;

You are basically removing transparency information

To make this transparent you have to keep and maintain alpha between passes. The easy fix would be to set

gl_FragColor.a = gl_FragColor.r

Otherwise you can also for instance calculate luminance from rgb and use that as alpha.

So then gl.clearColor(0, 0, 0, 0) would work

P.s. few words how shader works: you can imagine there are two types of effects one are called screen space (thouse are post processing) and the 3d ones.
So for screen space effects you apply plane to your view and uv cords of that plane are cords of your screen, the gpu interpolates uv by amount of pixels and calculates in parallel 2d array of pixels, so then by uv coords or masks and so on… you calculate color of every pixel on screen 60 times per second… Dunno if it makes sense but the simplest way to think about it that your vUv is a grid of pixels and you have to find color by checking or moving vUv

How to draw transparent background in webGL on canvas

The issue with the sample you linked to is that the sample itself is not transparent. It draw a background, then it draws sakura petals, then it applies a glow shader to give the petals a glow. This generates an opaque image so setting the canvas alpha to true (or not setting it all) won't make a difference.

To make it transparent comment out the following lines and change the background color

// gl.bindFramebuffer(gl.FRAMEBUFFER, renderSpec.mainRT.frameBuffer);
// gl.viewport(0, 0, renderSpec.mainRT.width, renderSpec.mainRT.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// renderBackground();
renderPointFlowers();
// renderPostProcess();

You can then possibly adjust the petal brightness changing this line

col *= mix(0.8, 1.0, pow(abs(coord.x), 0.3));

to this for example

col *= mix(1.8, 3.0, pow(abs(coord.x), 0.3));

Setting transparent background to this WebGL with OGL Flowmap effect?

There are two changes you need to make.

  1. In your Program declaration, you need to add transparent: true
  2. In your Fragment shader, change the output to gl_FragColor = texture2D(texture, uv);

The first change changes the blending type to use alpha - by default in WebGL blending is disabled.

The second uses the alpha channel of the texture. In the original example, only the rgb (red, green, blue) channels are used.

transparent background possible for webassembly gl canvas in browser?

Of course it's 100% possible because WebGL can do it. You can always fork the emscripten libraries,change a few lines, and use your fork. Unfortunately I can't give you an answer unless you specify how your are intializing OpenGL in emscripten. SDL? EGL? GLEW? GLUT? Each will have a different answer.

The first thing I would do is go look at the source for these libraries.

For SDL we see 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
},

and 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)
};

for EGL there's 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,

For GLUT there is 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)
};

which seem like they might lead to an answer?

Otherwise if you can't be bothered to read through the source then you can force it. Add this code to the top of your html file before any other scripts

<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>

I tested that with this sample, changed this line

  SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

to this

  SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);

and it worked for me.

Sample Image

Is it possible to draw a transparent canvas over WebGL content?

A WebGL canvas is just a canvas which is like any other HTML element. You can stack as many as you like (up to browser set limits or memory)

Here's 5 layers.

  1. A bottom div
  2. A webgl canvas
  3. A middle div
  4. A 2d canvas
  5. A top div

var gl = document.querySelector("#l1").getContext("webgl");gl.enable(gl.SCISSOR_TEST);gl.scissor(100, 50, 100, 90);gl.clearColor(0, 0.25, 0, 0.25);gl.clear(gl.COLOR_BUFFER_BIT);
var ctx = document.querySelector("#l3").getContext("2d");ctx.fillStyle = "rgba(255,0,255,0.25)";ctx.font = "55px san-serif";ctx.textAlign = "center";ctx.fillText("layer 3", 150, 50);
#l0, #l1, #l2, #l3, #l4 {  position: absolute;  left: 0;  top: 0;  width: 300px;  height: 150px;  border: 1px solid black;  text-align: center;  font-weight: bold;}
#l0 { color: rgba(255,0,0,0.25); font-size: 70px;}
#l2 { color: rgba(0,255,0,0.25); font-size: 60px;}
#l4 { color: rgba(0,0,255,0.25); font-size: 50px;}
<div id="l0">layer 0</div><canvas id="l1"></canvas><div id="l2">layer 2</div><canvas id="l3"></canvas><div id="l4">layer 4</div>

WebGL: Why does transparent canvas show clearColor color component when alpha is 0?

WebGL by default requires your colors to use premultiplied alpha. 1,0,0,0 is an invalid color because rgb of (1,0,0) * alpha of (0) = 0,0,0 not 1,0,0 so it's an invalid color and the spec is undefined for invalid colors. The results will be different on different browsers.

You have a few options

  • Tell WebGL your colors are not premultiplied

    gl = canvas.getContext("experimental-webgl", { premultipliedalpha: false });
  • Get rid of the alpha channel

    gl = canvas.getContext("experimental-webgl", { alpha: false });
  • Premultiply your alpha

    var r = 1;
    var g = 0;
    var b = 0;
    var a = 0;
    gl.clearColor(r * a, g * a, b * a, a);

    similarly in your shaders either pass in premultiplied colors or premultiply at the end.

    gl_FragColor = vec4(color.rgb * color.a, color.a);

Your blending settings have no effect. They only used when you call gl.drawXXX, they are not used when the canvas is composited with the background.



Related Topics



Leave a reply



Submit