Flow Map Shader for Unity Sprites

Hello there, it has been quite a long time since I wrote something on my blog:)

Today I have got a small neat thing to share – simple Flow Map Shader for Unity3D Sprites. To understand what I am talking about just have a look at this gif.

I also have a small repository on GitHub where I study shaders in Unity. This shader can be found there with example of usage.

flowmap

This kind of shader is usually used with two normal maps to simulate water and was first presented at SIGGRAPH 2010 by Valve. More information about the shader can be fount here. There is a nice tool out there for creating flow maps.

In this case, this is the texture that controls which parts of the image will be moving.

Flow Map Texture

So this is the shader code. I am not good at writing shaders and it can be not very efficient, but it does its job:

Shader "Custom/Flow Map"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        // Flow
        _FlowMap ("Flow Map", 2D) = "white" {}
        _FlowSpeed ("Flow Speed", float) = 0.05

        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    }

    SubShader
    {
        Tags
        { 
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ PIXELSNAP_ON
            #include "UnityCG.cginc"
            
            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
            };
            
            fixed4 _Color;

            v2f vert(appdata_t IN)
            {
                v2f OUT;

                OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;
                #ifdef PIXELSNAP_ON
                OUT.vertex = UnityPixelSnap (OUT.vertex);
                #endif

                return OUT;
            }

            sampler2D _MainTex;
            sampler2D _FlowMap;
            float _FlowSpeed;

            fixed4 frag(v2f IN) : SV_Target
            {
                float3 flowDir = tex2D(_FlowMap, IN.texcoord) * 2.0f - 1.0f;
                flowDir *= _FlowSpeed;

                float phase0 = frac(_Time[1] * 0.5f + 0.5f);
                float phase1 = frac(_Time[1] * 0.5f + 1.0f);

                half3 tex0 = tex2D(_MainTex, IN.texcoord + flowDir.xy * phase0);
                half3 tex1 = tex2D(_MainTex, IN.texcoord + flowDir.xy * phase1);

                float flowLerp = abs((0.5f - phase0) / 0.5f);
                half3 finalColor = lerp(tex0, tex1, flowLerp);

                fixed4 c = float4(finalColor, 1.0f) * IN.color;
                c.rgb *= c.a;
                return c;
            }
            ENDCG
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s