Unity UniStorm特效:雨滴屏幕互动体验

前言

本文主要介绍用unity实现雨水滴到屏幕的效果,文章介绍的是基础实现,读完这篇文章再去实现复杂效果会更得心应手些。我们先看更高级效果的图片:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time

一、实现过程

1.代码

先直接上代码,后面再做介绍:

登录后复制

Shader "Unlit/ScreenWater"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Size("Size", Range(0, 100)) = 1.0
		_T("Time", Float) = 1.0
		_Distortion("Distortion", Float) = -5
		_Blur("Blur", Range(0, 1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex 		: POSITION;
                float2 uv 			: TEXCOORD0;
            };

            struct v2f
            {
                float2 uv 			: TEXCOORD0;
                float4 vertex 		: SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			half _Size;
			half _T;
			half _Distortion;
			half _Blur;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
			
			// 求伪随机数
			half N21(half2 p){
				p = frac(p * half2(123.34, 345.45));
				p += dot(p, p + 34.345);
				return frac(p.x + p.y);
			}	
			
			half3 layer(half2 UV, half T){
				half t = fmod( _Time.y + T, 3600);
				half4 col = half4(0, 0, 0, 1.0);
				half aspect = half2(2, 1);
				half2 uv = UV * _Size * aspect;
				uv.y += t * 0.25;
				half2 gv = frac(uv) - 0.5;//-0.5,调整原点为中间
				half2 id = floor(uv);
				half n = N21(id); // 0 1
				t += n * 6.2831; //2PI

				half w = UV.y * 10;
				half x = (n - 0.5) * 0.8;
				x += (0.4 - abs(x)) * sin(3 * w) * pow(sin(w), 6) * 0.45;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;
				y -= (gv.x - x) * (gv.x - x);
				half2 dropPos = (gv - half2(x, y)) / aspect; //- half2(x,y) 为了移动
				half drop = smoothstep(0.05, 0.03, length(dropPos));

				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8;
				half trail = smoothstep(0.03, 0.01, length(trailPos));
				half fogTrail = smoothstep(-0.05, 0.05, dropPos.y);// 拖尾小水滴慢慢被拖掉了
				fogTrail *= smoothstep(0.5, y, gv.y);// 拖尾小水滴渐变消失
				fogTrail *= smoothstep(0.05, 0.04, abs(dropPos.x));
				trail *= fogTrail;
				//col += fogTrail * 0.5;
				//col += trail;
				//col += drop;
				//if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
				half2 offset = drop * dropPos +  trail * trailPos;
				return half3(offset, fogTrail);
			}

            half4 frag (v2f i) : SV_Target
            {
				half3 drops = layer(i.uv, _T);
				drops += layer(i.uv * 1.25 + 7.52, _T);
				drops += layer(i.uv * 1.35 + 1.54, _T);
				drops += layer(i.uv * 1.57 - 7.52, _T);			
				half blur = _Blur * 7 * (1 - drops.z);
				half4 col = tex2Dlod(_MainTex, half4(i.uv + drops.xy * _Distortion, 0, blur));
                return col;
            }
            ENDCG
        }
    }
}

下图显示了上面那段代码的效果,读者可自行在unity中先贴这段代码看,后面会做详细解析:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_02

2.代码分步解析

下面是实现步骤:

【1】先将uv平铺多次,为后面实现多个雨滴效果。

直接贴片元着色器代码:

登录后复制

half4 frag (v2f i) : SV_Target
            {
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(1, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				col.rg = gv;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_03


说明:A为从左下角的原点调整为中间的情况, _Size 为平铺多次的情况,读者可边看边在untiy上操作。

登录后复制

half2 aspect = half(2, 1);//长宽比

设置长宽比为2:1后,得到效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_04

【2】实现多个雨滴效果

直接贴片元着色器代码:

登录后复制

half4 frag (v2f i) : SV_Target
            {
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间

				half drop = smoothstep(0.05, 0.03, length(gv));//画圆, length(gv),可以理解为半径
				col += drop;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_shader_05


先附上smoothstep的解析,后续有时间会发文介绍glsl相关函数的理解,以及如何使用这些函数去实现复杂的效果。以下是smoothstep的解析:

我们先打开网址 Graphic Caculate,输入如图所示:

unity UniStorm unity UniStorm雨滴滴到屏幕_shader_06


smoothstep的公式就是s = k^2*(3 - 2k), 图上所示就是smoothstep(0.4, 0.6, x), 如果是反过来就是smoothstep(0.6, 0.4, x), 得到的就是如图所示:

unity UniStorm unity UniStorm雨滴滴到屏幕_shader_07


我们可以直接在 ShaderToy上演示输入如图所示代码:

unity UniStorm unity UniStorm雨滴滴到屏幕_shader_08


0.2 ->0.0 可以理解为简单的反向操作如图所示:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity UniStorm_09


【4】水滴移动

直接贴片元着色器代码:

登录后复制

half4 frag (v2f i) : SV_Target
            {
            	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half x = 0;
				half y = sin(t);//水珠是上下来回移动的
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				col += drop;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

改动下代码,让水滴是往下移动的:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half x = 0;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				col += drop;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

读者需要按照步骤去实现,更能理解算法表现的效果,帮助理解。上述代码中(2)得到的函数图是:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_10


读者可自行控制算法,调出更好的效果。

【4】水滴拖尾效果,拖尾水滴滑下
1、先画一个拖尾水滴,代码:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half x = 0;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half trail = smoothstep(0.03, 0.01, length(gv));//拖尾小水滴

				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				col += drop;
				col += trail;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_11


2、再计算移动,代码:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half x = 0;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
				half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				col += drop;
				col += trail;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_12


3、接下来我们将下部分拖尾水滴清理掉,边移动拖尾边消失,代码:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half x = 0;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
				half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				trail *= smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
				col += drop;
				col += trail;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity UniStorm_13


3、然后将水滴做个渐变,从上到下从无到有,代码:

登录后复制

... ...
				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				trail *= smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
				trail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
				col += drop;
				col += trail;
				... ...
				

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_14


【5】水滴做偏移,得到一种失真的效果,这时我们需要同时对x,y做偏移

1、同样,先贴上简单的效果,先改变下水滴的形状,代码:

登录后复制

half4 frag (v2f i) : SV_Target{
				... ...				
				half x = 0;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				y -= gv.x * gv.x;//改变水滴形状
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect				
				... ...               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_15


2、对x做偏移,代码如下:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = _Time.y;
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间
				
				half w = i.uv.y * 10;
				half x = sin(3 * w) * pow(sin(w), 6) * 0.45;//对x做些复杂的移动,(1)
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				y -= (gv.x - x) * (gv.x - x);
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
				half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				trail *= smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
				trail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
				col += drop;
				col += trail;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
               
				return col;
            }
            

(1)中的函数图:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_16

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity UniStorm_17

3、我们需要更随机些的效果,因此引入伪随机数:

登录后复制

// 求伪随机数
			half N21(half2 p){
				p = frac(p * half2(123.34, 345.45));
				p += dot(p, p + 34.345);
				return frac(p.x + p.y);
			}
			

先测试下伪随机数,代码:

登录后复制

... ... 
				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
				col *= 0; col += N21(i.uv); //测试代码
				... ...
				

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_18


可以得到噪点图,再把 col += N21(i.uv); 改为col += N21(id); 代码如下:

登录后复制

if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
				col *= 0; col += N21(id);
				

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_19


我们调整时间处理代码:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = fmod(_Time.y * _T, 7200);//每两个小时重置下,这样不会得到太大的数字,效果不平滑(3)
             	... ...
            }
            

(3)中如果数字太大会得到如图效果,效果很不好。

unity UniStorm unity UniStorm雨滴滴到屏幕_unity UniStorm_20


4、接下来我们完善下我们的效果,代码:

登录后复制

half4 frag (v2f i) : SV_Target{
             	half t = fmod(_Time.y * _T, 7200);//每两个小时重置下,这样不会得到太大的数字,效果不平滑(3)
				half4 col = half4(0, 0, 0, 1.0);
				half2 aspect = half2(3, 1);//长宽比
				half2 uv = i.uv * _Size * aspect;
				uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
				half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间

				half2 id = floor(uv);
				half n = N21(id); // 0 1
				t += n * 6.2831; //2PI

				half w = i.uv.y * 10;
				half x = (n - 0.5) * 0.8;; // -0.4 - 0.4
				x += (0.4 - abs(x)) * sin(3 * w) * pow(sin(w), 6) * 0.45;// 0.4- abs(x), 目的是限制在边框内摆动
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
				y -= (gv.x - x) * (gv.x - x);
				half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect
				
				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
				half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

				half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
				trail *= smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
				trail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
				col += drop;
				col += trail;

				if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
				//col *= 0; col += N21(id);
               
				return col;
            }
            

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_21


【6】水滴滑动拖尾雾效果

1、先实现第一步效果,代码:

登录后复制

half4 frag(v2f i) : SV_Target{
			  half t = fmod(_Time.y * _T, 7200);//每两个小时重置下,这样不会得到太大的数字,效果不平滑(3)
			  half4 col = half4(0, 0, 0, 1.0);
			  half2 aspect = half2(3, 1);//长宽比
			  half2 uv = i.uv * _Size * aspect;
			  uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
			  half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间

			  half2 id = floor(uv);
			  half n = N21(id); // 0 1
			  t += n * 6.2831; //2PI

			  half w = i.uv.y * 10;
			  half x = (n - 0.5) * 0.8;; // -0.4 - 0.4
			  x += (0.4 - abs(x)) * sin(3 * w) * pow(sin(w), 6) * 0.45;// 0.4- abs(x), 目的是限制在边框内摆动
			  half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
			  y -= (gv.x - x) * (gv.x - x);
			  half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect

			  half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
			  trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
			  half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

			  half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
			  half fogTrail = smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
			  fogTrail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
			  trail *= fogTrail;
			  col += fogTrail * 0.5;

			  col += drop;
			  col += trail;

			  if (gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
			  //col *= 0; col += N21(id);

			  return col;
			}
			

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_shader_22


2、我们需要讲上图的两边雾的效果缩小下,代码:

登录后复制

half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
			  half fogTrail = smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
			  fogTrail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
			  fogTrail *= smoothstep(0.05, 0.04, abs(dropPos.x));// 两边雾的效果缩小下
			  trail *= fogTrail;
			  col += fogTrail * 0.5;
			  

下图显示了上面那段代码的效果, 可以看出两边雾被缩小了:

unity UniStorm unity UniStorm雨滴滴到屏幕_unity_23


【7】结合主纹理,得到简答的真实水滴屏幕效果

1、直接贴代码:

登录后复制

half4 frag(v2f i) : SV_Target{
			  half t = fmod(_Time.y * _T, 7200);//每两个小时重置下,这样不会得到太大的数字,效果不平滑(3)
			  half4 col = half4(0, 0, 0, 1.0);
			  half2 aspect = half2(3, 1);//长宽比
			  half2 uv = i.uv * _Size * aspect;
			  uv.y += t * 0.25; //水滴周期移动的同时,uv也往下移动,这样就能做到水滴往下移动的效果
			  half2 gv = frac(uv) - 0.5;//-0.5,将左下角的原点调整为中间

			  half2 id = floor(uv);
			  half n = N21(id); // 0 1
			  t += n * 6.2831; //2PI

			  half w = i.uv.y * 10;
			  half x = (n - 0.5) * 0.8;; // -0.4 - 0.4
			  x += (0.4 - abs(x)) * sin(3 * w) * pow(sin(w), 6) * 0.45;// 0.4- abs(x), 目的是限制在边框内摆动
			  half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;//将y改为更复杂些的移动(2)
			  y -= (gv.x - x) * (gv.x - x);
			  half2 dropPos = (gv - half2(x, y)) / aspect;// 移动水滴,除以aspect是因为之前的uv*aspect

			  half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
			  trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8; // -0.5是将半圆调整为完整圆
			  half trail = smoothstep(0.03, 0.01, length(trailPos));//拖尾小水滴

			  half drop = smoothstep(0.05, 0.03, length(dropPos));//画圆, length(gv),可以理解为半径
			  half fogTrail = smoothstep(-0.05, 0.05, dropPos.y);//将下部分拖尾水滴清理掉,边移动拖尾边消失
			  fogTrail *= smoothstep(0.5, y, gv.y);//将水滴做个渐变,从上到下从无到有, 0.5是以gv为坐标的,顶部0.5,底部-0.5
			  fogTrail *= smoothstep(0.05, 0.04, abs(dropPos.x));
			  trail *= fogTrail;
			  col += fogTrail * 0.5;

			  col += drop;
			  col += trail;

			  //if (gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
			  //col *= 0; col += N21(id);

			  half2 offset = drop * dropPos + trail * trailPos;
			  half4 finalColor = tex2D(_MainTex, i.uv + offset * _Distortion);

			  return finalColor;
			}
			

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_opengl_24


2、接下来我们需要对主纹理采样进行处理,得到一种雾屏的效果

代码:

登录后复制

half2 offset = drop * dropPos + trail * trailPos;
			half blur = _Blur * 7 * (1 - fogTrail);//这里为啥1-fogTrail,读者可去试下,得到拖尾雾效果是相反的
			//直接将tex2D改为tex2dlod, _Blur控制模糊程度
			//tex2Dlod(ref: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509680%28v=vs.85%29.aspx)
			half4 finalColor = tex2Dlod(_MainTex, half4(i.uv + offset * _Distortion, 0, blur ));
			

下图显示了上面那段代码的效果:

unity UniStorm unity UniStorm雨滴滴到屏幕_Time_25


3、接下来我们需要整理下代码:

登录后复制

half3 dropLayer(half2 UV, half T){
				half t = fmod( _Time.y + T, 3600);
				half4 col = half4(0, 0, 0, 1.0);
				half aspect = half2(2, 1);
				half2 uv = UV * _Size * aspect;
				uv.y += t * 0.25;
				half2 gv = frac(uv) - 0.5;//-0.5,调整原点为中间
				half2 id = floor(uv);
				half n = N21(id); // 0 1
				t += n * 6.2831; //2PI

				half w = UV.y * 10;
				half x = (n - 0.5) * 0.8;
				x += (0.4 - abs(x)) * sin(3 * w) * pow(sin(w), 6) * 0.45;
				half y = -sin(t + sin(t + sin(t) * 0.5)) * 0.45;
				y -= (gv.x - x) * (gv.x - x);
				half2 dropPos = (gv - half2(x, y)) / aspect; //- half2(x,y) 为了移动
				half drop = smoothstep(0.05, 0.03, length(dropPos));

				half2 trailPos = (gv - half2(x, t * 0.25)) / aspect; //- half2(x,y) 为了移动
				trailPos.y = (frac(trailPos.y * 8) - 0.5) / 8;
				half trail = smoothstep(0.03, 0.01, length(trailPos));
				half fogTrail = smoothstep(-0.05, 0.05, dropPos.y);// 拖尾小水滴慢慢被拖掉了
				fogTrail *= smoothstep(0.5, y, gv.y);// 拖尾小水滴渐变消失
				fogTrail *= smoothstep(0.05, 0.04, abs(dropPos.x));
				trail *= fogTrail;
				//col += fogTrail * 0.5;
				//col += trail;
				//col += drop;
				//if(gv.x > 0.48 || gv.y > 0.49) col = half4(1.0, 0, 0, 1.0); // 辅助线
				half2 offset = drop * dropPos +  trail * trailPos;
				return half3(offset, fogTrail);
			}

            half4 frag (v2f i) : SV_Target
            {
				half3 drops = dropLayer(i.uv, _T);		
				half blur = _Blur * 7 * (1 - drops.z);
				half4 col = tex2Dlod(_MainTex, half4(i.uv + drops.xy * _Distortion, 0, blur));
                return col;
            }
            

【8】现在的雨滴效果还不够,我们需要叠加几层,效果会更丰富些

登录后复制

half4 frag (v2f i) : SV_Target
            {
				half3 drops = dropLayer(i.uv, _T);
				//这里的参数读者可自行测试控制
				drops += dropLayer(i.uv * 1.25 + 7.52, _T);
				drops += dropLayer(i.uv * 1.35 + 1.54, _T);
				drops += dropLayer(i.uv * 1.57 - 7.52, _T);			
				half blur = _Blur * 7 * (1 - drops.z);
				half4 col = tex2Dlod(_MainTex, half4(i.uv + drops.xy * _Distortion, 0, blur));
                return col;
            }
            

上面得到的效果就是开篇的那种效果了,读者还可以结合抓屏效果去实现更好的效果,性能上这块算法也没比较复杂的指令运算,移动端可以使用的,读者液可自行使用renderdoc等GPU测试工具测试下即可。


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空