1 June
How can I make the canvas transparent on WebGL?
3D
Programming
min. read
Transparent canvas on WebGL using Unity?
When doing development for WebGL, there is sometimes this question. Can we make the canvas transparent? Can we make HTML elements be in front of the canvas, but also can we make them behind the canvas?
The answer to this question is a surprising yes! This is true not only for Legacy Renderer but also for URP!
Transparent canvas for Legacy Renderer in WebGL
In the legacy renderer, it’s pretty simple to achieve that. There are 2 parts to make this work.
- JavaScript code in *.jslib
- The camera clear mode changed
I recommend starting it first in an “empty” project, to remove all possible dependencies on the first try!
JavaScript injection
Create a new file called transparentBackground.jslib
and put there this code
// Create new module that we will inject into framework.js file
var transparentBackground = {
// Create a method glClear - this will overwrite default behaviour
glClear: function(mask)
{
// If mask of the layer is set to "depth only"
if (mask == 0x00004000)
{
var v = GLctx.getParameter(GLctx.COLOR_WRITEMASK);
// And the color is "transparent"
if (!v[0] && !v[1] && !v[2] && v[3])
// We do nothing
return;
}
// else we clear the mask to prevent tearing
GLctx.clear(mask);
}
};
// Merge our module into framework.js
mergeInto(LibraryManager.library, transparentBackground);
Camera clear mode
Take all cameras that should render with a transparent background and change their “Clear Mode” to “DepthOnly”
To do this from within Unity you can just select a given option or use code on a camera component
void Start()
{
GetComponent<Camera>().clearFlags = CameraClearFlags.Depth;
}
Transparent canvas for Universal Rendering Pipeline (URP)
Here first 2 steps look exactly the same. We need to inject the same JS code and set camera clear flags to DepthOnly. But here it’s a bit more complicated than that…
JavaScript injection
Create a new file called transparentBackground.jslib
and put there this code
// Create new module that we will inject into framework.js file
var transparentBackground = {
// Create a method glClear - this will overwrite default behaviour
glClear: function(mask)
{
// If mask of the layer is set to "depth only"
if (mask == 0x00004000)
{
var v = GLctx.getParameter(GLctx.COLOR_WRITEMASK);
// And the color is "transparent"
if (!v[0] && !v[1] && !v[2] && v[3])
// We do nothing
return;
}
// else we clear the mask to prevent tearing
GLctx.clear(mask);
}
};
// Merge our module into framework.js
mergeInto(LibraryManager.library, transparentBackground);
Camera clear mode and …
As before we need to set the camera mode to Depth Only, but in URP this setting is hidden, and cannot be selected from the normal menu.
In order to change Camera mode manually, you need to switch inspector to debug mode
As before this can be changed from code mutch easier
void Start()
{
GetComponent<Camera>().clearFlags = CameraClearFlags.Depth;
}
But this time this is not enough!
Camera post-processing
Unfortunately in URP postprocessing transforms all pixels – including transparent ones and forces the background to be rendered and our JavaScript injection cannot detect it, so we need to disable that as well.
To do that we can do it per camera from settings or via script. In the camera settings, we need to find Post Processing and toggle it Off.
From the code, since this is part of URP we need to access UniversalAdditionalCameraData
component and disable it there.
var universalAdditionalCameraData = GetComponent<UniversalAdditionalCameraData>() as UniversalAdditionalCameraData;
universalAdditionalCameraData.renderPostProcessing = false;
The full solution for URP
The full solution to do this per camera would look like this
using UnityEngine;
public class SetupCameraForWebGLTransparency : MonoBehaviour
{
private void Awake()
{
GetComponent<Camera>().clearFlags = CameraClearFlags.Depth;
var universalAdditionalCameraData = GetComponent<UniversalAdditionalCameraData>() as UniversalAdditionalCameraData;
universalAdditionalCameraData.renderPostProcessing = false;
}
}
Pitfalls of a transparent canvas
Unfortunately, this method has its downsides that are hard to overcome but can be overcome with a “smart” design.
Transparency
This is the biggest issue that we encountered. If you opted for a transparent canvas all your transparent pixels will be gone! Even ones that are 99% solid. If they have any alpha they will just disappear. Unless they will be rendered above solid objects.
So as described in the image above, to make objects visible you need to make them either 100% solid (they can have a transparent shader, but it’s not recommended). Or make them as part of the opaque background.
You can think of this as such.
House windows view from the outside will have the house as a background, so they will be visible. But when we enter the house and we will look through the window to the outside (and there will be no environment) the windows will be gone.
Unity UI
Since we want to have a transparent background so that we can have immersive HTML UI, this point probably doesn’t bother anyone. But if you already have your UI in Unity and not HTML then you should know that you will have problems with transparency as stated before. All transparent (even 99% solid) pixels would be invisible in this scenario. So you would have to redesign your UI to make sure that you have only hard edges that are not fading by transparency.
Post-processing
Unfortunately, all post-processing in URP and some in Legacy will cause to have a background from Unity rendered. This is because, the post-processing pipeline (at least in URP) will by default take the color of the background, even though we want it to have it cleared.
You can recreate some effects using HTML like vignette, and color grading. For others, you would need to resort to custom shaders, but some effects will not be achievable at all because of the Transparency issue. Bloom, Chromatic abbreviation, etc… And even if they would be possible, they would require a custom post-processing pipeline that would respect transparent pixels. Not to mention that post-processing on the Web would kill mobile performance.
Summary
Transparent HTML canvas in Unity WebGL is possible! No more changes are required, and the other good part is that this is a fully dynamic effect. You can toggle it on and off based on your current needs. Need to render it transparent to showcase a “product” but then you want to “visualize” it with background and with all the post-processes? It’s all possible!
Have trouble with implementation? Reach out to us! We will be glad to help 🙂
https://prographers.com/contact
This effect was possible because of Ricardo Arango who made a blog post on it back in the day on Unity forum.
This effect works on all versions of Unity from Unity 5 to latest 2022 (currently beta) and I expect that it will work for a long time until we get some major rework of the WebGL player.
Let's talk
I agree that my data in this form will be sent to [email protected] and will be read by human beings. We will answer you as soon as possible. If you sent this form by mistake or want to remove your data, you can let us know by sending an email to [email protected]. We will never send you any spam or share your data with third parties.
I agree that my data in this form will be sent to [email protected] and will be read by human beings. We will answer you as soon as possible. If you sent this form by mistake or want to remove your data, you can let us know by sending an email to [email protected]. We will never send you any spam or share your data with third parties.