前一端时间写了一些有关下雨效果的Shader的,感觉实现的效果很不错,所以把它们分享一下,主要参考表面积水效果 RainSurface和Rainy Surface Shader Part 1: Ripples。下面是视频:


一些下雨的效果(Unity Shader)


动图:


unity 雨松momo unity下雨效果_#pragma


大致可分为两个部分,一是地面的水坑和涟漪,二是石板的流水效果。雨滴效果是我用粒子瞎做的。


先来看第一部分,以下是Shader代码:

Shader "Custom/WeatherFloor"
{
    Properties
    {
        _RainColor ("Water Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal("Normal",2D)="bump"{}
        [NoScaleOffset]_RippleTex("Ripple Tex", 2D) = "white" {}
        [NoScaleOffset]_MaskTex("Mask Tex", 2D) = "white" {}
        _RippleScale("Ripple Scale",Range(1,10)) =1
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Ripple ("Ripple Strength", Range(0,1)) = 0.0
        _WaterRange("Water Range", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Normal;
        sampler2D _RippleTex;
        //R通道代表了涟漪生成的范围,并且带有淡出的效果,
        //GB两个通道是高度,差不多就是法线图的效果,
        //A通道用来存储时间差,从白到黑不同的颜色值代表了不同的时间。
        sampler2D _MaskTex;

        struct Input
        {
            half2 uv_MainTex;
            half2 uv_Normal;
            half2 uv_FlowMap;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _RainColor;
        half _RippleScale;
        half _Ripple;
        half _WaterRange;

        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_INSTANCING_BUFFER_END(Props)

        half3 ComputeRipple(half2 uv,half t)
        {   
            //波纹贴图采样,并把采样的高度值扩展到-1到1
            half4 ripple=tex2D(_RippleTex,uv);
            ripple.gb=ripple.gb*2-1;
            //获取波纹的时间,从A通道获取不同的波纹时间,
            //frac返回输入值的小数部分。
            half dropFrac=frac(ripple.a+t);
            //把时间限制在R通道内,(dropFrac-1+ripple.r<0时,计算final时0*UNITY_PI)
            half timeFrac=dropFrac-1+ripple.r;
            //做淡出处理
            half dropFactor=1- saturate(dropFrac);
            //计算最终的高度,用一个sin计算出随时间的振幅,修改一下值就知道什么效果了
            half final=dropFactor*sin(clamp(timeFrac*9,0,4)*UNITY_PI);
            return half3(ripple.gb*final,1);
        }

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            half3 ripple=ComputeRipple(IN.uv_MainTex*_RippleScale,_Time.y)*_Ripple;
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            half3 normal=UnpackNormal(tex2D(_Normal,IN.uv_MainTex));
            fixed mask=tex2D(_MaskTex,IN.uv_Normal).r;

			half rainMask=pow(saturate(lerp(-0.6,3,_WaterRange)-(1-mask)*2),8);

            fixed3 waterColor=_RainColor.rgb*c.rgb;
            o.Albedo = lerp(c.rgb,waterColor,rainMask);
            o.Normal=normalize(lerp(normal,half3(0,0,1),rainMask)+ripple*rainMask);
            o.Metallic = lerp(_Metallic,0.5,rainMask);
            o.Smoothness = lerp(_Glossiness,1,rainMask);
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

ComputeRipple计算出的波形大致会是这个样子:

unity 雨松momo unity下雨效果_shader_02


一个周期里只会出现两次波峰,刚好符合效果的两圈涟漪。这里有需要一张涟漪图:

unity 雨松momo unity下雨效果_#pragma_03


CSDN不能上传tga格式的,并且会打水印,可以在网盘里拿,链接:https://pan.baidu.com/s/1XyH0yyS5u-a9DgEo4E9rNQ 提取码:4fj6。

水洼的原理是改变改变水洼处的法线、金属度、粗糙度的信息,并没有太多复杂的地方,可以用一张噪声图来控制水洼的位置,我现在是直接用一张噪声图来做。

接下来是水流效果:

unity 雨松momo unity下雨效果_unity_04


以下是Shader代码:

Shader "Custom/Flow"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        [NoScaleOffset]_NormalTex("Normal Map",2D )="bump"{}
        _RainColor("Water Color", Color) = (1,1,1,1)
        _FlowMap("FlowMap",2D)="white"{}
        [NoScaleOffset]_FlowNormal("Flow Normal Map",2D )="bump"{}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _FlowRange("Flow Water Range",Range(0,1))=0.5
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Cull Back

        CGPROGRAM

        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _NormalTex;
        sampler2D _FlowMap;
        sampler2D _FlowNormal;

        struct Input
        {
            float2 uv_MainTex;
            half2 uv_FlowMap;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        fixed _FlowRange;
        fixed4 _RainColor;

        UNITY_INSTANCING_BUFFER_START(Props)
        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;

            half2 flowUV=IN.uv_FlowMap;
            fixed flowG=tex2D(_FlowMap,flowUV).g;
            flowUV=flowUV+half2(0,_Time.y*0.4);
            fixed flowB=tex2D(_FlowMap,flowUV).b;
            fixed flowMask=saturate(_FlowRange-flowB);

            half3 flowNormal=UnpackNormal(tex2D(_FlowNormal,IN.uv_FlowMap));
            //flowNormal.xy=-flowNormal.xy;
            half3 normal=UnpackNormal(tex2D(_NormalTex,IN.uv_MainTex));
            //flowNormal=normalize(normal+lerp(half3(0,0,1),flowNormal,flowMask));
            flowNormal=normalize(lerp(normal,flowNormal,flowMask));

            o.Albedo = c.rgb+_RainColor.rgb*flowG*flowMask;
            o.Normal=flowNormal;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}