
This tutorial coversorder-independent blending.
It continues the discussion inSection “Transparency” and solves some problems of standard transparency. If you haven't read that tutorial, you should read it first.

As noted inSection “Transparency”, the result of blending often (in particular for standard alpha blending) depends on the order in which triangles are rendered and therefore results in rendering artifacts if the triangles are not sorted from back to front (which they usually aren't). The term “order-independent transparency” describes various techniques to avoid this problem. One of these techniques is order-independent blending, i.e. the use of a blend equation that does not depend on the order in which triangles are rasterized. There are two basic possibilities: additive blending and multiplicative blending.
The standard example for additive blending are double exposures as in the images in this section: colors are added such that it is impossible (or at least very hard) to say in which order the photos were taken. Additive blending can be characterized in terms of the blend equation introduced inSection “Transparency”:
float4 result = SrcFactor * fragment_output + DstFactor * pixel_color;
wherefragment_output is the output of the fragment shader, andpixel_color is the color that is already in the framebuffer whileSrcFactor andDstFactor are determined by a line in Unity's ShaderLab syntax:
Blend {code forSrcFactor} {code forDstFactor}
For additive blending, the code forDstFactor has to beOne and the code forSrcFactor must not depend on the pixel color in the framebuffer; i.e., it can beOne,SrcColor,SrcAlpha,OneMinusSrcColor, orOneMinusSrcAlpha.
An example is:
Shader"Cg shader using additive blending"{SubShader{Tags{"Queue"="Transparent"}// draw after all opaque geometry has been drawnPass{CullOff// draw front and back facesZWriteOff// don't write to depth buffer// in order not to occlude other objectsBlendSrcAlphaOne// additive blendingCGPROGRAM#pragma vertex vert#pragma fragment fragfloat4vert(float4vertexPos:POSITION):SV_POSITION{returnUnityObjectToClipPos(vertexPos);}float4frag(void):COLOR{returnfloat4(1.0,0.0,0.0,0.2);}ENDCG}}}
An example for multiplicative blending in photography is the use of multiple uniform grey filters: the order in which the filters are put onto a camera doesn't matter for the resulting attenuation of the image. In terms of the rasterization of triangles, the image corresponds to the contents of the framebuffer before the triangles are rasterized, while the filters correspond to the triangles.
When specifying multiplicative blending in Unity with the line
Blend {code forSrcFactor} {code forDstFactor}
the code forSrcFactor has to beZero and the code forDstFactor must depend on the fragment color; i.e., it can beSrcColor,SrcAlpha,OneMinusSrcColor, orOneMinusSrcAlpha. A typical example for attenuating the background with the opacity specified by the alpha component of fragments would useOneMinusSrcAlpha for the code forDstFactor:
Shader"Cg shader using multiplicative blending"{SubShader{Tags{"Queue"="Transparent"}// draw after all opaque geometry has been drawnPass{CullOff// draw front and back facesZWriteOff// don't write to depth buffer// in order not to occlude other objectsBlendZeroOneMinusSrcAlpha// multiplicative blending// for attenuation by the fragment's alphaCGPROGRAM#pragma vertex vert#pragma fragment fragfloat4vert(float4vertexPos:POSITION):SV_POSITION{returnUnityObjectToClipPos(vertexPos);}float4frag(void):COLOR{returnfloat4(1.0,0.0,0.0,0.2);}ENDCG}}}
Finally, it makes good sense to combine multiplicative blending for the attenuation of the background and additive blending for the addition of colors of the triangles in one shader by combining the two passes that were presented above. This can be considered an approximation to alpha blending forsmall opacities, i.e.small values of alpha, if one ignores attenuation of colors of the triangle mesh by itself.
Shader"Cg shader using order-independent blending"{SubShader{Tags{"Queue"="Transparent"}// draw after all opaque geometry has been drawnPass{CullOff// draw front and back facesZWriteOff// don't write to depth buffer// in order not to occlude other objectsBlendZeroOneMinusSrcAlpha// multiplicative blending// for attenuation by the fragment's alphaCGPROGRAM#pragma vertex vert#pragma fragment fragfloat4vert(float4vertexPos:POSITION):SV_POSITION{returnUnityObjectToClipPos(vertexPos);}float4frag(void):COLOR{returnfloat4(1.0,0.0,0.0,0.2);}ENDCG}Pass{CullOff// draw front and back facesZWriteOff// don't write to depth buffer// in order not to occlude other objectsBlendSrcAlphaOne// additive blending to add colorsCGPROGRAM#pragma vertex vert#pragma fragment fragfloat4vert(float4vertexPos:POSITION):SV_POSITION{returnUnityObjectToClipPos(vertexPos);}float4frag(void):COLOR{returnfloat4(1.0,0.0,0.0,0.2);}ENDCG}}}
Note that the order of the two passes is important: first the background is attenuated and then colors are added.
Congratulations, you have reached the end of this tutorial. We have looked at:
If you still want to know more