【Unity】【シェーダ】ノーマルマップをフローマップで流す

ノーマルマップをフローマップで流す方法です。

シェーダ

早速ですがシェーダです。

Shader "FlowingNormalMap"
{
    Properties
    {
        _NormalMap ("Normal Map", 2D)                                = "bump" {}
        _FlowMap ("Flow Map", 2D)                                    = "white" {}
        _FlowSpeed ("Flow Speed", float)                            = 1.0
        _FlowIntensity ("Flow Intensity", float)                    = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }
        
        Pass
        {
            Blend One Zero
            Lighting Off

            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
            
           #include "UnityCG.cginc"
            
            sampler2D _NormalMap;
            float4 _NormalMap_ST;
            sampler2D _FlowMap;
            float _FlowIntensity;
            float _FlowSpeed;

            struct appdata
            {
                float4 vertex       : POSITION;
                float2 uv           : TEXCOORD0;
                float4 normal       : NORMAL;
                half4 tangent       : TANGENT;
            };

            struct v2f
            {
                float4 vertex       : SV_POSITION;
                half2 normalUv      : TEXCOORD0;
                half2 flowUv        : TEXCOORD1;
            };
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex        = UnityObjectToClipPos(v.vertex);
                o.normalUv      = TRANSFORM_TEX(v.uv, _NormalMap);
                o.flowUv        = v.uv;

                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // 流れの方向を取得
                float2 flowDir                  = tex2D(_FlowMap, i.flowUv) - 0.5;
                flowDir                         *= _FlowIntensity;
                float progress1                    = frac(_Time.x * _FlowSpeed);
                float progress2                    = frac(_Time.x * _FlowSpeed + 0.5);
                float2 flowUv1                  = i.normalUv + flowDir * progress1;
                float2 flowUv2                  = i.normalUv + flowDir * progress2;
                float lerpRate                 = abs((0.5 - progress1) / 0.5);
                // フローマップで計算したUVに応じてノーマルマップをサンプリング
                half3 normal1                   = UnpackNormal(tex2D(_NormalMap, flowUv1));
                half3 normal2                   = UnpackNormal(tex2D(_NormalMap, flowUv2));
                // ノーマルマップをブレンド
                float2 pd                       = lerp(normal1.xy / normal1.z, normal2.xy / normal2.z, lerpRate);
                float3 normal                   = normalize(float3(pd, 1));
                
                return half4(normal, 1);
            }
            ENDCG
        }
    }
}

フローマップで求めたUVでノーマルマップをサンプリングするところまでは特に変わったことはやっていません。
ノーマルマップをブレンドする際に、偏微分の考え方を使う方法を取っています。

light11.hatenadiary.com

結果

結果は次のようになります。

f:id:halya_11:20181216144948g:plain

接空間の法線を出力してるだけなので分かりづらいですが、正常に流れています。

関連

light11.hatenadiary.com

light11.hatenadiary.com