- Home /
Unity's default shaders' blending is messed up?
When you have to deal with rendering transparency correctly and specially when using a renderTexture, it is crucial to perform correct blending based on pre-multiplying the RGB with the alpha channel. More on that here.
As a general rule, the blending mode for alpha channel should ALWAYS be: One OneMinusSrcAlpha
. The blending used for RGB should either be 'One OneMinusSrcAlpha' or 'SRC_ALPHA OneMinusSrcAlpha', depending on whether the source is alpha pre-multiplied or not.
Let's see what unity does. The standard sprite shader uses One OneMinusSrcAlpha
for RGB and alpha and premultiplies the rgb with the alpha in the fragment shader. This produces correct RGB and alpha values.
However, the Unlit-Transparent
shader uses SrcAlpha OneMinusSrcAlpha
which results in wrong alpha values. If you render on a solid surface and simply don't care about the resulting alpha, you won't notice the problem. If you render on a renderTexture and then render this on screen, you will notice the problem.
I have created a simple unity project that demonstrates the issue by rendering 2 semi-transparent grey sprites on a render texture. You can find it here and go through the readme file..
Also, when you render the renderTexture the rgb values are already premultiplied. Thus you want to use One OneMinusSrcAlpha
for rgb. I had to create a "premultiplied" iteration of the standard sprite shader to make this work.
So, my question is if I am missing something and Unity provides a proper way to deal with this or you have to be really careful when dealing with transparency and adjust the shaders yourself?
Answer by tanoshimi · May 16, 2016 at 06:28 PM
I'm not sure what the problem is? The built-in shaders provide a range of examples... if they don't behave the way you want to (and it sounds like you have already identified the way you would prefer), then you just make your own shader.
The problem is that if you want to render something with transparency on a render texture and render that on screen, you won't get it right by default. I think something as trivial as this, should not be that easy to do wrong (see this question caused by wrong blending modes).
Also I don't understand why unity chose "srcAlpha One$$anonymous$$inusSrcAlpha" blending mode for both RGB and alpha in many shaders, as I can't think of an example where you want to blend the alpha channel this way. Unless of course, this is faster than specifying different blending modes for RGB and alpha.
If you want to propose a change to the default shader blend mode, you should log this at https://feedback.unity3d.com/
Thank's for the idea @tanoshimi . I posted my feedback: https://feedback.unity3d.com/suggestions/proper-blending-modes-regarding-alpha-channel
I have been learning shaders for use with rendertextures, and as you said, with the rendertextures it became apparent something was wrong in the shaders. I had been using the docs to modify the default sprite shader, and in them it says SrcAlpha One$$anonymous$$inusSrcAlpha is "Traditional transparency", but that went against my understanding of colors, and it took a lot of being puzzled, and having to check out wikipedia's alpha compositing math, to confirm SrcAlpha One$$anonymous$$inusSrcAlpha is incorrect. https://docs.unity3d.com/$$anonymous$$anual/SL-Blend.html If it's more efficient the wrong way, at least the docs shouldn't be confusing and call it "Traditional transparency", if it's just a tradeoff for speed. :/