Unity Shader: Dissolve Shader


In this article I'd like to show you a quick and easy way to implement the dissolve effect.
Mind you, the code is not optimized to make it easier (hopefully) to understand.
Let's begin!

The Dissolve Texture

First of all we need a dissolve texture and we can generate it ourselves using Photoshop Cloud filter.
Here's mine:

The Shader

Add a new Standard Surface Shader in Unity.
Add two new input properties to our shader:
1
2
3
4
5
6
7
8
Properties
{
     //...Other shader properties
 
     //Dissolve Shader Properties
     _DissolveTexture ("Dissolve Texture", 2D) = "white" {}
     _Amount("Dissolve Amount", Range(0, 1)) = 0
}
  • _DissolveTexture is where we put our dissolve texture
  • _Amount represents the progress of dissolving our object (0 = visible, 1 = disappeared)
In the surf function is where the magic happens!
We get the dissolve_value by sampling the color of our _DissolveTexture using the tex2D function.
Because the _DissolveTexture is in grayscale, we can get the color value from any of the RGB components, I use red.
The clip() function is what makes the pixels dissolve: it discards any pixel with a color value < 0.
Our dissolve_value is in the range of [0,1], where darker colors tend to 0 and lighter ones tend to 1.
To get values that are less than zero we subtract the _Amount value from the dissolve_value so that pixels will gradually dissolve (first the darker pixels then the lighter ones) as the _Amount value increases.
Here's the complete code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Shader "Mistwork/Basic Dissolve"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _DissolveTexture("Dissolve Texture", 2D) = "white" {}
        _Amount("Dissolve Amount", Range(0, 1)) = 0
        _BurnSize ("Burn Size", Range(0.0, 1.0)) = 0.03
  _BurnColor ("Burn Color", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard addshadow

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _DissolveTexture;
        half _Amount;
        half _BurnSize;
  float4 _BurnColor;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

            //Get the dissolve value by sampling the _DissolveTexture and get its red value
            half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r;
            //Subtract to the _Amount to get value < 0
            dissolve_value -= _Amount;
            //Discard pixels with value < 0
            clip(dissolve_value);


            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

At line 19 we use addshadow because otherwise the shadow will remain visible even if the object is completely dissolved!

Add the burn effect

A cool effect we can add to our dissolve shader is a burn effect around the dissolved areas.
First of all, add two new input properties to our shader:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Properties
{
 //...Other shader properties
 
 //Dissolve Shader Properties
 _DissolveTexture ("Dissolve Texture", 2D) = "white" {}
 _Amount("Dissolve Amount", Range(0, 1)) = 0
 _BurnSize ("Burn Size", Range(0.0, 1.0)) = 0.03
 _BurnColor ("Burn Color", Color) = (1, 1, 1, 1)
}

  • _BurnSize is the size of the burn effect around the dissolved areas
  • _BurnColor is the color of the burn effect
The burn effect is the same as the dissolve effect but instead of dissolving the pixels it adds an emission color. 
If the dissolve_value was the same as the _BurnSize value, we wouldn't see the emission color because it would be discarded. That's why we check if the _BurnSize value is bigger than the dissolve_value, if it is we emit the emission color.
Here's the final code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Shader "Mistwork/Basic Dissolve"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _DissolveTexture("Dissolve Texture", 2D) = "white" {}
        _Amount("Dissolve Amount", Range(0, 1)) = 0
        _BurnSize ("Burn Size", Range(0.0, 1.0)) = 0.03
  _BurnColor ("Burn Color", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard addshadow

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _DissolveTexture;
        half _Amount;
        half _BurnSize;
  float4 _BurnColor;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

            //Get the dissolve value by sampling the _DissolveTexture and get its red value
            half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r;
            //Subtract to the _Amount to get value < 0
            dissolve_value -= _Amount;
            //Discard pixels with value < 0
            clip(dissolve_value);

            //Add the burn effect
            if (_BurnSize > dissolve_value)
    o.Emission = _BurnColor;


            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}


Comments

Popular posts from this blog

GLSL Shader in Maya Part 1

Unity Shader: Toon Water Shader

Unity Shader: Spherical Mask Dissolve