Skip to content

Problem with Transparency in RenderTexture, ScreenCapture, or ReadPixels – Unity

I encountered a weird issue in Unity where RenderTextures, ScreenCaptures, and even ReadPixels would have alpha values less than 1 even with solid backgrounds! After a lot of research and experimentation, I found the cause of the problem. It actually wasn’t a bug at all. It’s due to how Unity handles transparency. Buckle up and get ready for some learning.

Side note: I discovered all this while building my Ultimate Screenshot Tool. Check it out! This stuff is cool to learn either way, but imo it’s definitely worth having a solid solution that’ll handle all the odd corner cases to be found in screen capture.

Unity Uses Additive Alpha Blending

Due to the complexities of transparencies in 3D spaces, Unity uses additive alpha blending. (Documentation)
An example of this formula is as follows:
Color resultColor = foregroundColor * foregroundColor.a + backgroundColor * (1f – foregroundColor.a);

Here’s some examples of the results of the calculations:

Color backgroundColor = new Color32(128, 128, 128, 255);
Color foregroundColor = new Color32(255, 255, 255, 128);
Color resultColor = foregroundColor * foregroundColor.a + backgroundColor * (1f - foregroundColor.a);
Debug.Log(string.Format("Result color: {0} {1} {2} {3}", ((Color32)resultColor).r, ((Color32)resultColor).g, ((Color32)resultColor).b, ((Color32)resultColor).a));
Debug.Log(string.Format("Result color: {0} {1} {2} {3}", resultColor.r, resultColor.g, resultColor.b, resultColor.a));

The above code produces:
Result color: 191 191 191 191
Result color: 0.7519569 0.7519569 0.7519569 0.7500038

Changing the foreground alpha to 10 produces:
Result color: 132 132 132 245
Result color: 0.5214918 0.5214918 0.5214918 0.9623222

Changing the foreground alpha to 240 produces:
Result color: 247 247 247 240
Result color: 0.9707036 0.9707036 0.9707036 0.9446367

In other words, the resulting alpha is foregroundColor.a * foregroundColor.a + backgroundColor.a * (1f – foregroundColor.a); Even with backgroundColor.a = 1, the resulting alpha is foregroundColor.a * foregroundColor.a + (1f – foregroundColor.a);

As you can see, despite having a solid color background the resulting color is partially transparent. Also, alpha values at either end of the range produce more solid results that mid range alpha values. The same result will happen to games with partially transparent elements.

Other Blending Methods

A traditional method of blending in less complex situations is as follows:

float sourceAlpha = foregroundColor.a;
float destAlpha = 1f - foregroundColor.a;
float resultAlpha = sourceAlpha + destAlpha * backgroundColor.a;
Color resultColor = (foregroundColor * sourceAlpha + backgroundColor * backgroundColor.a * destAlpha) / resultAlpha;
resultColor.a = resultAlpha;

Rewritten the alpha value is:
resultColor.a = foregroundColor.a + backgroundColor.a * (1f – foregroundColor.a);
When backgroundColor.a = 1, resultColor.a = foregroundColor.a + (1f – foregroundColor.a) = 1

Since this blending method gives us the values we want, we can use it instead of Unity’s standard.

Solution

If you want a solid image without transparency, you could always simply manually override the alpha values to 1.

If you want an image with a transparent background, you could avoid putting any transparencies in front of the objects that should be solid and those elements will remain solid in your chosen method of capture.

If you have a more complex case, such as a case where areas with transparent overlays need to be 100% solid and other areas should have be partially transparent. You’ll need to do a bit more customization.

One way to get the exact method of blending you want is to separate elements of your game into separate cameras, with the solid elements drawn with an alpha value of 1 on one camera and the transparent elements on a separate camera and manually blend them to get the result you want.

This works, because Unity uses its additive alpha blend on the elements within a camera. However, the camera layers are combined manually with an alternate alpha blending technique.

Alternative Solution

If you’d rather a simpler method of getting screen captures (with a load more extra features), check out my Ultimate Screenshot Tool. It’ll handle the cases above, export and save files on standalone, mobile, and web, add custom logos or hide debug text, cutout select portions of the screen, use quick shot hotkeys, rapidly take screenshots at multiple high fidelity resolutions, and much more!

Published inCode ExamplesDevelopment Tips

Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *