生活随笔
收集整理的這篇文章主要介紹了
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
100Pass
{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;half2 id
= floor(uv
);half n
= N21(id
); t
+= n
* 6.2831; 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
; half drop
= smoothstep(0.05, 0.03, length(dropPos
));half2 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; 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
;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中先貼這段代碼看,后面會做詳細解析:
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;col
.rg
= gv
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
下圖顯示了上面那段代碼的效果:
說明:A為從左下角的原點調整為中間的情況, _Size 為平鋪多次的情況,讀者可邊看邊在untiy上操作。
half2 aspect
= half(2, 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;half drop
= smoothstep(0.05, 0.03, length(gv
));col
+= drop
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
下圖顯示了上面那段代碼的效果:
先附上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;half x
= 0;half y
= sin(t
);half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;half drop
= smoothstep(0.05, 0.03, length(dropPos
));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; half2 gv
= frac(uv
) - 0.5;half x
= 0;half y
= -sin(t
+ sin(t
+ sin(t
) * 0.5)) * 0.45;half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;half drop
= smoothstep(0.05, 0.03, length(dropPos
));col
+= drop
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
讀者需要按照步驟去實現,更能理解算法表現的效果,幫助理解。上述代碼中(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; half2 gv
= frac(uv
) - 0.5;half x
= 0;half y
= -sin(t
+ sin(t
+ sin(t
) * 0.5)) * 0.45;half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;half trail
= smoothstep(0.03, 0.01, length(gv
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));col
+= drop
;col
+= trail
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
下圖顯示了上面那段代碼的效果:
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; half2 gv
= frac(uv
) - 0.5;half x
= 0;half y
= -sin(t
+ sin(t
+ sin(t
) * 0.5)) * 0.45;half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;half2 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));col
+= drop
;col
+= trail
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
下圖顯示了上面那段代碼的效果:
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; half2 gv
= frac(uv
) - 0.5;half x
= 0;half y
= -sin(t
+ sin(t
+ sin(t
) * 0.5)) * 0.45;half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;half2 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));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
;}
下圖顯示了上面那段代碼的效果:
3、然后將水滴做個漸變,從上到下從無到有,代碼:
... ...half drop
= smoothstep(0.05, 0.03, length(dropPos
));trail
*= smoothstep(-0.05, 0.05, dropPos
.y
);trail
*= smoothstep(0.5, y
, gv
.y
);col
+= drop
;col
+= trail
;... ...
下圖顯示了上面那段代碼的效果:
【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
-= gv
.x
* gv
.x
;half2 dropPos
= (gv
- half2(x
, y
)) / aspect
;... ... return col
;}
下圖顯示了上面那段代碼的效果:
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; half2 gv
= frac(uv
) - 0.5;half w
= i
.uv
.y
* 10;half 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 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));trail
*= smoothstep(-0.05, 0.05, dropPos
.y
);trail
*= smoothstep(0.5, y
, gv
.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)中的函數圖:
下圖顯示了上面那段代碼的效果:
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
); ... ...
下圖顯示了上面那段代碼的效果:
可以得到噪點圖,再把 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
);
下圖顯示了上面那段代碼的效果:
我們調整時間處理代碼:
half4 frag
(v2f i
) : SV_Target
{half t
= fmod(_Time
.y
* _T
, 7200);... ...}
(3)中如果數字太大會得到如圖效果,效果很不好。
4、接下來我們完善下我們的效果,代碼:
half4 frag
(v2f i
) : SV_Target
{half t
= fmod(_Time
.y
* _T
, 7200);half4 col
= half4(0, 0, 0, 1.0);half2 aspect
= half2(3, 1);half2 uv
= i
.uv
* _Size
* aspect
;uv
.y
+= t
* 0.25; half2 gv
= frac(uv
) - 0.5;half2 id
= floor(uv
);half n
= N21(id
); t
+= n
* 6.2831; half w
= i
.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 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));trail
*= smoothstep(-0.05, 0.05, dropPos
.y
);trail
*= smoothstep(0.5, y
, gv
.y
);col
+= drop
;col
+= trail
;if(gv
.x
> 0.48 || gv
.y
> 0.49) col
= half4(1.0, 0, 0, 1.0); return col
;}
下圖顯示了上面那段代碼的效果:
【6】水滴滑動拖尾霧效果
1、先實現第一步效果,代碼:
half4
frag(v2f i
) : SV_Target
{half t
= fmod(_Time
.y
* _T
, 7200);half4 col
= half4(0, 0, 0, 1.0);half2 aspect
= half2(3, 1);half2 uv
= i
.uv
* _Size
* aspect
;uv
.y
+= t
* 0.25; half2 gv
= frac(uv
) - 0.5;half2 id
= floor(uv
);half n
= N21(id
); t
+= n
* 6.2831; half w
= i
.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 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));half fogTrail
= smoothstep(-0.05, 0.05, dropPos
.y
);fogTrail
*= smoothstep(0.5, y
, gv
.y
);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); return col
;}
下圖顯示了上面那段代碼的效果:
2、我們需要講上圖的兩邊霧的效果縮小下,代碼:
half drop
= smoothstep(0.05, 0.03, length(dropPos
));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;
下圖顯示了上面那段代碼的效果, 可以看出兩邊霧被縮小了:
【7】結合主紋理,得到簡答的真實水滴屏幕效果
1、直接貼代碼:
half4
frag(v2f i
) : SV_Target
{half t
= fmod(_Time
.y
* _T
, 7200);half4 col
= half4(0, 0, 0, 1.0);half2 aspect
= half2(3, 1);half2 uv
= i
.uv
* _Size
* aspect
;uv
.y
+= t
* 0.25; half2 gv
= frac(uv
) - 0.5;half2 id
= floor(uv
);half n
= N21(id
); t
+= n
* 6.2831; half w
= i
.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 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; trailPos
.y
= (frac(trailPos
.y
* 8) - 0.5) / 8; half trail
= smoothstep(0.03, 0.01, length(trailPos
));half drop
= smoothstep(0.05, 0.03, length(dropPos
));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
+= drop
;col
+= trail
;half2 offset
= drop
* dropPos
+ trail
* trailPos
;half4 finalColor
= tex2D(_MainTex
, i
.uv
+ offset
* _Distortion
);return finalColor
;}
下圖顯示了上面那段代碼的效果:
2、接下來我們需要對主紋理采樣進行處理,得到一種霧屏的效果
代碼:
half2 offset
= drop
* dropPos
+ trail
* trailPos
;half blur
= _Blur
* 7 * (1 - fogTrail
);half4 finalColor
= tex2Dlod(_MainTex
, half4(i
.uv
+ offset
* _Distortion
, 0, blur
));
下圖顯示了上面那段代碼的效果:
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;half2 id
= floor(uv
);half n
= N21(id
); t
+= n
* 6.2831; 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
; half drop
= smoothstep(0.05, 0.03, length(dropPos
));half2 trailPos
= (gv
- half2(x
, t
* 0.25)) / aspect
; 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
;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測試工具測試下即可。
總結
本文實現的雨水滴到屏幕效果相對來說還是不夠豐富的,如果讀者想實現更復雜的效果可以參考 raindrop , ShaderToy鏈接。
通過學習筆者寫的,再去理解更復雜的效果會容易上手些。后續筆者會繼續推出有詳細解析的文章,碼字不易,覺得寫的不錯的可以點贊關注支持下,激勵下筆者,謝謝啦。
參考
raindrop
ShaderToy鏈接
總結
以上是生活随笔為你收集整理的Unity 雨水滴到屏幕效果的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。