Get an 20% OFF using the RELEASE code on your book purchase. For a limited time.

Introduction to the shader programming language

3.1.7. SubShader Blending

This post is also available in…

Blending is the process of mixing two pixels into one. Its command is compatible with both Built-in RP and Scriptable RP

Blending occurs in a stage called “merging” which combines the final color of a pixel (those pixels that have been processed in the fragment shader stage) with its depth. This stage, which occurs at the end of the render pipeline; after the fragment shader stage, is where the stencil-buffer, z-buffer and color blending are executed.

By default, this property is not written in our shader since it is an optional function and is used mainly when we work with transparent objects, e.g., when we must draw a pixel with a low opacity level in front of another. 

Its default value is “Blend Off”, but we can activate it to generate different types of Blending, like those that appear in photoshop. 

Its syntax is as follows:

Blend [SourceFactor] [DestinationFactor]

“Blend” is a function that requires two values ​​called “factors” for its operation and based on an equation it will be the final color that we will obtain on-screen. According to the official documentation in Unity, the equation that defines the value of the Blending is as follows:

B = SrcFactor * SrcValue [OP] DstFactor * DstValue.

To understand this operation, we must consider the following: The fragment shader stage occurs first and then, as an optional process; the merging stage.

SrcValue” (source value), which has been processed in the fragment shader stage, corresponds to the pixel’s RGB color output. 

DstValue” (destination value) corresponds to the RGB color that has been written in the “destination buffer”, better known as “render target” (SV_Target). When the Blending options are not active in our shader, SrcValue overwrites DstValue. However, if we activate this operation, both colors are mixed to get a new color, which overwrites the previous DstValue

SrcFactor” (source factor) and “DstFactor” (destination factor) are vectors of three dimensions that vary depending on their configuration. Their main function is to modify the ​​ SrcValue and DstValue values to achieve interesting effects. 

Some factors that we can find in the Unity documentation are:

  • Off, disables Blending options. 
  • One, (1, 1, 1).
  • Zero, (0, 0, 0). 
  • SrcColor is equal to the RGB values ​​of the SrcValue
  • SrcAlpha is equal to the Alpha value of the SrcValue
  • OneMinusSrcColor 1 minus the RGB values ​​of the SrcValue (1 – R, 1 – G, 1 – B).
  • OneMinusSrcAlpha 1 minus the Alpha of SrcValue (1 – A, 1 – A, 1- A). 
  • DstColor is equal to the RGB values ​​of the DstValue
  • DstAlpha is equal to the Alpha value of the DstValue
  • OneMinusDstColor 1 minus the RGB values ​​of the DstValue (1 – R, 1 – G, 1 – B).
  • OneMinusDstAlpha 1 minus the Alpha of the DstValue (1 – A, 1 – A, 1- A).

It is worth mentioning that the Blending of the Alpha channel is carried out in the same way in which we process the RGB color of a pixel, but it is done in an independent process because it is not used frequently. Likewise, by not performing this process, the writing on the render target is optimized. 

Let’s exemplify the above explanation as follows.

Let’s say we have an RGB color pixel with the values  [0.5R, 0.45G, 0.35B]. This color has been processed by the fragment shader stage, therefore it corresponds to the DstValue. Now, we multiply this value by the “SrcFactor One” which equals [1, 1, 1]. Every number multiplied by “1” results in the same value, therefore, the result between the SrcFactor and the DstValue is the same as its initial value.

B = [0.5R, 0.45G, 0.35B] [OP] DstFactor * DstValue.

“OP” refers to the operation that we are going to perform. By default, it is set to “Add”. 

B = [0.5R, 0.45G, 0.35B] + DstFactor * DstValue.

Once we have obtained the value of the first operation, it is overwritten by DstValue, therefore, is set to the same color [0.5R, 0.45G, 0.35B]. So, we will multiply this color by the “DstFactor DstColor”, which is equal to the current value we have in the DstFactor.

DstFactor [0.5R, 0.45G, 0.35B] * DstValue [0.5R, 0.45G, 0.35B] = [0.25R, 0.20G, 0.12B].

Finally, the output colour for the pixel is.

B = [0.5R, 0.45G, 0.35B] + [0.25R, 0.20G, 0.12B].
B = [0.75R, 0.65G, 0.47B]

If we want to activate Blending in our shader, we must use the Blend command followed by SrcFactor and then DstFactor. Its syntax is the following:

Shader “InspectorPath / shaderName”
{
    Properties {} …
    SubShader
    {
        Tags { "Queue" = "Transparent" “RenderType”=”Transparent”} 
        Blend SrcAlpha OneMinusSrcAlpha
    }
}

If we want to use Blending in our shader, it will be necessary to add and modify the “Render Queue”. As we already know, the default value of the “Queue” tag is “Geometry”, which means that our object will appear opaque. If we want our object to look transparent, then we must first change the “Queue” to “Transparent” and then add some kind of blending. 

The most common types of blending are the following:

Blend SrcAlpha OneMinusSrcAlpha     // Common transparent blending 
Blend One One                       // Additive blending color 
Blend OneMinusDstColor One          // Mild additive blending color 
Blend DstColor Zero                 // Multiplicative blending color 
Blend DstColor SrcColor             // Multiplicative blending x2 
Blend SrcColor One                  // Blending overlay 
Blend OneMinusSrcColor One          // Soft light blending 
Blend Zero OneMinusSrcColor         // Negative color blending

A different way to configure our Blending is through the dependency “UnityEngine.Rendering.BlendMode”. This line of code allows us to change, from the inspector, the Blending of an object in the material. To set it up first we must add the “Toggle Enum” to our properties and then declare both the SrcFactor and the DstFactor.

Its syntax is as follows:

// [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend (“Source Factor”, Float) = 1
// [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend (“Destination Factor”, Float) = 1

Shader “InspectorPath / shaderName”
{
    Properties 
    {
        [Enum(UnityEngine.Rendering.BlendMode)] 
            _SrcBlend (“SrcFactor”, Float) = 1
        [Enum(UnityEngine.Rendering.BlendMode)] 
            _DstBlend (“DstFactor”, Float) = 1
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" “RenderType”=”Transparent”} 
        Blend [_SrcBlend] [_DstBlend]
    }
}

Blending options can be written in different fields: within the SubShader field or the Pass field, the position will depend on the number of passes and the final result that we need.

Follow us to stay informed about all the latest news, updates, and more.

Join the group to share your experiences with other developers.

Subscribe to our channel and keep learning game dev!

jettelly-logo

Jettelly Team

We are a team of indie developers with more than 9 years of experience in video games. As an independent studio, we have developed Nom Noms in which we published with Hyperbeard in 2019. We are currently developing The Unity Shader Bible.

Follow us on our social networks.