Unity Shader: Spherical Mask Dissolve


Spherical Mask Dissolve Shader

This shader is the combination of the two previous shader, the Dissolve shader and the Spherical Mask shader to get a "reveal world" kind of shader, something like you have experienced in games like Beyond Eyes.

If you remember, in the Dissolve shader we used a _DissolveTexture to get a dissolve_value.
Because the dissolve_value is in the range of (0,1) we needed an _Amount value to be subtracted from the dissolve_value so that the clip() function can discard all the pixels that has a dissolve_value < 0.
In the Spherical Mask Dissolve shader we don't have an _Amount value, instead we have to compute it!
To compute the _Amount value (that in this shader is called amount), we use the technique showed in the Spherical Mask Shader.
In the Spherical Mask Shader we checked if a pixel was inside of the player radius of action, if it was we color it, if it wasn't we let it in grayscale.
Here we use the same logic to define if a pixel has to be shown or be discarded.
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Shader "Mistwork/SphericalMaskDissolve"
{
    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

        //Spherical Mask Dissolve Properties
        _PlayerPos ("Player Position", Vector) = (0, 0, 0, 0)
        _Radius ("Dissolve Radius", Range(0, 100)) = 0
        _Softness("Dissolve Softness", Range(0, 100)) = 0
        _DissolveTex ("Dissolve Texture", 2D) = "white" {}
        _BurnSize ("Burn Size", Range(0.0, 2.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 fullforwardshadows

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

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_DissolveTex;
            //Pass the vertex position in world space
            float3 worldPos;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        //Spherical Mask Dissolve Properties
        sampler2D _DissolveTex;
        float4 _PlayerPos;
        half _Radius;
        half _Softness;
        half _BurnSize;
        fixed4 _BurnColor;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            //Sample the dissolve_value from the _DissolveTexture
            half dissolve_value = tex2D(_DissolveTex, IN.uv_DissolveTex).r;

            //For every vertex of this object, compute its distance from the player
            half d = distance(_PlayerPos, IN.worldPos);
            //Compute the amount value by subtracting the _Radius value
            half amount = d - _Radius;
            //Apply the softness
            amount /= -_Softness;
            //Clamp the effect value to a range (0, 1)
            amount = saturate(amount);

            //Because we have applied the inverse of the _Softness, the order in the subtraction has changed compared to the one in the Dissolve shader
            clip(amount - dissolve_value);

            if (amount - dissolve_value < _BurnSize)
                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"
}

The Script


We need a script to pass the player position to the shader but this script comes in handy also for another cool effect we can add to our shader!
Wouldn't be cool if could animate the "reveal effect" even if the player stands still as shown in the picture above?
One simple way is to animate the Dissolve texture by simply increasing its texture offset at runtime.
Here's the code of the script we have to attach to our object:

 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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SphericalMaskDissolve : MonoBehaviour
{
    [SerializeField]
    private GameObject player;
    private float textureOffset = 0.0f;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        GetComponent<Renderer>().material.SetVector("_PlayerPos", player.transform.position);
        AnimateDissolveBurn();
    }

    private void AnimateDissolveBurn()
    {
        textureOffset += 0.001f;
        GetComponent<Renderer>().material.SetTextureOffset("_DissolveTex", new Vector2(textureOffset, textureOffset));
    }
}


Comments

Popular posts from this blog

GLSL Shader in Maya Part 1

Unity Shader: Toon Water Shader