当前位置:   article > 正文

Unity 雨水滴到屏幕效果_unity 平面下雨后处理

unity 平面下雨后处理


前言

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

在这里插入图片描述

一、实现过程

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
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

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

在这里插入图片描述

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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

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

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

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

在这里插入图片描述

【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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

在这里插入图片描述
先附上smoothstep的解析,后续有时间会发文介绍glsl相关函数的理解,以及如何使用这些函数去实现复杂的效果。以下是smoothstep的解析:
我们先打开网址 Graphic Caculate,输入如图所示:

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

在这里插入图片描述
我们可以直接在ShaderToy上演示输入如图所示代码:

在这里插入图片描述
0.2 ->0.0 可以理解为简单的反向操作如图所示:

在这里插入图片描述
【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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

            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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

在这里插入图片描述
读者可自行控制算法,调出更好的效果。

【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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

在这里插入图片描述
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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

在这里插入图片描述
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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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

在这里插入图片描述
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;
				... ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

在这里插入图片描述
【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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

在这里插入图片描述
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

(1)中的函数图:

在这里插入图片描述

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

在这里插入图片描述

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);
			}	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

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

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

在这里插入图片描述
可以得到噪点图,再把 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);
  • 1
  • 2

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

在这里插入图片描述
我们调整时间处理代码:

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

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

在这里插入图片描述
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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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

在这里插入图片描述
【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;
			}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

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

在这里插入图片描述
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

在这里插入图片描述
【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;
			}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

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

在这里插入图片描述
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 ));
  • 1
  • 2
  • 3
  • 4
  • 5

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

在这里插入图片描述
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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

【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;
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

总结

本文实现的雨水滴到屏幕效果相对来说还是不够丰富的,如果读者想实现更复杂的效果可以参考 raindropShaderToy链接
通过学习笔者写的,再去理解更复杂的效果会容易上手些。后续笔者会继续推出有详细解析的文章,码字不易,觉得写的不错的可以点赞关注支持下,激励下笔者,谢谢啦。

参考

raindrop
ShaderToy链接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/636855
推荐阅读
相关标签
  

闽ICP备14008679号