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

Unity Shader 窗前雨滴效果衍生(表面水滴附着)

程序员文章站 2022-03-31 19:09:30
...

霓虹中国视频截图

Unity Shader 窗前雨滴效果衍生(表面水滴附着)
在B站上发现大佬做的UE4渲染视频,感觉这种赛博朋克风格的渲染非常的好看,同时也对场景中汽车表面附着上的一层水珠效果感到惊艳。

现实中的水珠附着效果

Unity Shader 窗前雨滴效果衍生(表面水滴附着)

实现思路

上一篇我们是实现了窗前雨滴的效果,所以我在想能不能通过窗前雨滴的做法衍生来实现场景中水珠附着的效果。

1.首先创建一个Cube来作为实现效果的物体

Unity Shader 窗前雨滴效果衍生(表面水滴附着)

2.创建一个Shader开始着色器的编写

先定义一下需要用到的属性

	Properties
	{
		_MainTex ("Main Texture", 2D) = "white" {}   //水珠图片
		_MoreRainAmount("Droplet Amount",Range(0, 1)) = 1  //水珠数量
		_FixedDroplet("Fixed Droplet",Range(0 ,1)) = 0.7   //固定水珠
		_DropletSize("Droplet Size",Range(0 ,1)) = 0.4    //水珠大小
		_DropletDensity("Droplet Density",Range(0 ,10)) = 1.85   //水珠疏密
		_Speed("Droplet Speed",Range(0 ,1)) = 1   //滑落速度
	}

改写一下窗前雨滴的shader

			float3 N13(float p) {
				float3 p3 = frac(float3(p,p,p) * float3(.1031,.11369,.13787));
				p3 += dot(p3, p3.yzx + 19.19);
				return frac(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
			}
			float4 N14(float t) {
				return frac(sin(t*float4(123., 1024., 1456., 264.))*float4(6547., 345., 8799., 1564.));
			}
			float N(float t) {
				return frac(sin(t*12345.564)*7658.76);
			}
			float Saw(float b, float t) {
				return smoothstep(0., b, t)*smoothstep(1., b, t);
			}

			float2 DropLayer2(float2 uv, float t) {
				float2 UV = uv;
				
				uv.y += t * 0.75;
				float2 a = float2(6, 1);
				float2 grid = a * 2.;
				float2 id = floor(uv * grid);
				
				float colShift = N(id.x); 
				uv.y += colShift;
				
				id = floor(uv * grid);
				float3 n = N13(id.x * 35.2 + id.y * 2376.1);
				float2 st = frac(uv * grid) - float2(0.5, 0);
				
				float x = n.x - 0.5;
				
				float y = UV.y * 20;
				float wiggle = sin(y + sin(y));
				x += wiggle * (0.5 - abs(x)) * (n.z - 0.5);
				x *= _FixedDroplet;
				float ti = frac(t + n.z);
				y = (Saw(0.85, ti) - 0.5) * 0.9 + 0.5;
				float2 p = float2(x, y);
				
				float d = length((st - p) * a.yx);
				
				float mainDrop = smoothstep(_DropletSize, 0, d);
				
				float r = sqrt(smoothstep(1, y, st.y));
				float cd = abs(st.x - x);
				float trail = smoothstep(0.23 * r, 0.15 * r * r, cd);
				float trailFront = smoothstep(-0.02, 0.02, st.y - y);
				trail *= trailFront * r * r;
				
				y = UV.y;
				float trail2 = smoothstep(0.2 * r, 0.0, cd);
				float droplets = max(0, (sin(y * (1 - y) * 120) - st.y)) * trail2 * trailFront*n.z;
				y = frac(y*10.)+(st.y-.5);
				float dd = length(st-float2(x, y));
				droplets = smoothstep(.3, 0., dd);
				float m = mainDrop+droplets*r*trailFront; 
				
				return float2(m, trail);
			}

			float StaticDrops(float2 uv, float t) {
				uv *= 40.;
				
				float2 id = floor(uv);
				uv = frac(uv)-.5;
				float3 n = N13(id.x * 107.45 + id.y * 3543.654);
				float2 p = (n.xy-.5)*.7;
				float d = length(uv-p);
				
				float fade = Saw(.025, frac(t+n.z));
				float c = smoothstep(.3, 0., d)*frac(n.z*10.)*fade;
				return c;
			}
			
			float2 Drops(float2 uv, float t, float l0, float l1, float l2) {
				float s = StaticDrops(uv, t)*l0; 
				float2 m1 = DropLayer2(uv, t)*l1;
				float2 m2 = DropLayer2(uv * _DropletDensity, t) * l2;
				
				float c = s + m1.x + m2.x;
				c = smoothstep(0.3, 1, c);
				
				return float2(c, max(m1.y * l0, m2.y * l1));
			}

			float2 DropsDynamic(float2 uv, float t, float l1, float l2)
			{
				float2 m1 = DropLayer2(uv, t)*l1;
				float2 m2 = DropLayer2(uv*1.75, t)*l2;
				
				float c = m1.x+m2.x;
				c = smoothstep(.4, 1., c);
				
				return float2(c, max(0, m2.y*l1));
			}

实现效果截图

Unity Shader 窗前雨滴效果衍生(表面水滴附着)
Unity Shader 窗前雨滴效果衍生(表面水滴附着)
想要达到上述视频中的效果,还需要对纹理的模糊处理,可以参考一下 UWA的《Unity Shader之磨砂玻璃与水雾玻璃效果》水雾玻璃效果。
相关链接:https://blog.csdn.net/UWA4D/article/details/90268304

Shader源码

Shader "Kirk/Droplet"
{
	Properties
	{
		_MainTex ("Main Texture", 2D) = "white" {}   //水珠
		_MoreRainAmount("Droplet Amount",Range(0, 1)) = 1
		_FixedDroplet("Fixed Droplet",Range(0 ,1)) = 0.7
		_DropletSize("Droplet Size",Range(0 ,1)) = 0.4
		_DropletDensity("Droplet Density",Range(0 ,10)) = 1.85
		_Speed("Droplet Speed",Range(0 ,1)) = 1
	}

	SubShader
	{
		Tags { "Queue"="Transparent" "RenderType"="Opaque" }

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float4 scrPos : TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				float3 normal : TEXCOORD3;
				float3 worldPos : TEXCOORD4;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _FixedDroplet;
			float _MoreRainAmount;
			float _DropletSize;
			float _DropletDensity;
			float _Speed;

			float3 N13(float p) {
				float3 p3 = frac(float3(p,p,p) * float3(.1031,.11369,.13787));
				p3 += dot(p3, p3.yzx + 19.19);
				return frac(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
			}
			float4 N14(float t) {
				return frac(sin(t*float4(123., 1024., 1456., 264.))*float4(6547., 345., 8799., 1564.));
			}
			float N(float t) {
				return frac(sin(t*12345.564)*7658.76);
			}
			float Saw(float b, float t) {
				return smoothstep(0., b, t)*smoothstep(1., b, t);
			}

			float2 DropLayer2(float2 uv, float t) {
				float2 UV = uv;
				
				uv.y += t * 0.75;
				float2 a = float2(6, 1);
				float2 grid = a * 2.;
				float2 id = floor(uv * grid);
				
				float colShift = N(id.x); 
				uv.y += colShift;
				
				id = floor(uv * grid);
				float3 n = N13(id.x * 35.2 + id.y * 2376.1);
				float2 st = frac(uv * grid) - float2(0.5, 0);
				
				float x = n.x - 0.5;
				
				float y = UV.y * 20;
				float wiggle = sin(y + sin(y));
				x += wiggle * (0.5 - abs(x)) * (n.z - 0.5);
				x *= _FixedDroplet;
				float ti = frac(t + n.z);
				y = (Saw(0.85, ti) - 0.5) * 0.9 + 0.5;
				float2 p = float2(x, y);
				
				float d = length((st - p) * a.yx);
				
				float mainDrop = smoothstep(_DropletSize, 0, d);
				
				float r = sqrt(smoothstep(1, y, st.y));
				float cd = abs(st.x - x);
				float trail = smoothstep(0.23 * r, 0.15 * r * r, cd);
				float trailFront = smoothstep(-0.02, 0.02, st.y - y);
				trail *= trailFront * r * r;
				
				y = UV.y;
				float trail2 = smoothstep(0.2 * r, 0.0, cd);
				float droplets = max(0, (sin(y * (1 - y) * 120) - st.y)) * trail2 * trailFront*n.z;
				y = frac(y*10.)+(st.y-.5);
				float dd = length(st-float2(x, y));
				droplets = smoothstep(.3, 0., dd);
				float m = mainDrop+droplets*r*trailFront; 
				
				return float2(m, trail);
			}

			float StaticDrops(float2 uv, float t) {
				uv *= 40.;
				
				float2 id = floor(uv);
				uv = frac(uv)-.5;
				float3 n = N13(id.x * 107.45 + id.y * 3543.654);
				float2 p = (n.xy-.5)*.7;
				float d = length(uv-p);
				
				float fade = Saw(.025, frac(t+n.z));
				float c = smoothstep(.3, 0., d)*frac(n.z*10.)*fade;
				return c;
			}
			
			float2 Drops(float2 uv, float t, float l0, float l1, float l2) {
				float s = StaticDrops(uv, t)*l0; 
				float2 m1 = DropLayer2(uv, t)*l1;
				float2 m2 = DropLayer2(uv * _DropletDensity, t) * l2;
				
				float c = s + m1.x + m2.x;
				c = smoothstep(0.3, 1, c);
				
				return float2(c, max(m1.y * l0, m2.y * l1));
			}

			float2 DropsDynamic(float2 uv, float t, float l1, float l2)
			{
				float2 m1 = DropLayer2(uv, t)*l1;
				float2 m2 = DropLayer2(uv*1.75, t)*l2;
				
				float c = m1.x+m2.x;
				c = smoothstep(.4, 1., c);
				
				return float2(c, max(0, m2.y*l1));
			}

			v2f vert (appdata v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.scrPos = ComputeScreenPos(o.pos);
				o.normal = v.normal;
				o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
				o.worldNormal  = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				return o;
			}

			fixed4 frag (v2f _iParam) : SV_Target
			{
				float4 fragColor = 0;
        		
				float2 uv = _iParam.uv;
				float2 UV = _iParam.uv;
				float3 M = 2;
				float T = (_Time.y + M.x * 2) * _Speed;

				float t = T*(.2+0.1*_MoreRainAmount);

				float rainAmount = M.y;

				uv *= 0.5;

				float staticDrops = smoothstep(-.5, 1., rainAmount) * 2.;
				float layer1 = smoothstep(.25, .75, rainAmount);
				float layer2 = smoothstep(.0, .5, rainAmount);

				float2 n = float2(0, 0);
				float2 c = Drops(uv, t, staticDrops, layer1, layer2);
				float2 e = float2(0.001, 0.);
				float cx = Drops(uv + e, t, staticDrops, layer1, layer2).x;
				float cy = Drops(uv + e.yx, t, staticDrops, layer1, layer2).x;
				n += float2(cx - c.x, cy - c.x);
				float moreRainAmount = 1.25 + 1.25 * _MoreRainAmount;
				for(float i = 1.25; i < moreRainAmount; i+=0.25)
				{
					float2 _c = DropsDynamic(uv, t*i, layer1, layer2);
					float _cx = DropsDynamic(uv + e, t*i, layer1, layer2).x;
					float _cy = DropsDynamic(uv + e.yx, t*i, layer1, layer2).x;
					n += float2(_cx - _c.x, _cy - _c.x);
				}

				float blend = (n.x + n.y)*(1.75 + _MoreRainAmount);
				float3 col = tex2D(_MainTex, UV + n).rgb;
				fragColor = float4(col, blend);
				return fragColor;
			}
			ENDCG
		}
	}
}