欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity Shader 两个关于下雨的效果分享

程序员文章站 2024-02-14 09:46:22
...

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

一些下雨的效果(Unity Shader)


动图:
Unity Shader 两个关于下雨的效果分享
大致可分为两个部分,一是地面的水坑和涟漪,二是石板的流水效果。雨滴效果是我用粒子瞎做的。
先来看第一部分,以下是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;

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

ComputeRipple计算出的波形大致会是这个样子:
Unity Shader 两个关于下雨的效果分享
一个周期里只会出现两次波峰,刚好符合效果的两圈涟漪。这里有需要一张涟漪图:
Unity Shader 两个关于下雨的效果分享
CSDN不能上传tga格式的,并且会打水印,可以在网盘里拿,链接:https://pan.baidu.com/s/1XyH0yyS5u-a9DgEo4E9rNQ 提取码:4fj6。
水洼的原理是改变改变水洼处的法线、金属度、粗糙度的信息,并没有太多复杂的地方,可以用一张噪声图来控制水洼的位置,我现在是直接用一张噪声图来做。
接下来是水流效果:
Unity Shader 两个关于下雨的效果分享
以下是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"
}

这里也需要两张特制的贴图,链接:https://pan.baidu.com/s/14XhpRExfjQ7bo0kdBjivLg,提取码:ktfj。
具体的思路是用一张流动的遮罩对法线进行叠加,造成雨水流动的假象,方法很简单但实现的效果很好。
好了今天的????就摸到这了,溜了溜了。
Unity Shader 两个关于下雨的效果分享