转载作品

窗户雨滴效果

Lui2019 发表于   2020-08-21 15:04:24
2107
1
11

https://zhuanlan.zhihu.com/p/60884288 黄小明

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】

这是一个老外制作的一个水滴在玻璃上流淌的shader,效果非常好

所以偷偷学了过来,因为内容有点长我分为两个部分

我会尽可能详细解释制作思路和部分函数

(都是为了你,开心吗?)

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】

-------------------------

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
shader效果

首先我们先仔细看下效果,要大概有一个基础的思路,不去考虑细节,最简单的基础的去解释下这幅画面,是不是雨滴在做一个向下的运动

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
思路图

那么接下来开始我们从第一步,做一个水滴,让他在UV上运动,然后我们再一步步加效果

-------------------------

首先我们来做一些准备工作

一双勤劳的手

一张图片

一颗刚刚被甩的心(这个很重要,心境没到位,怎么能做的好?)

不BB了,我们开始,准备工作自己想办法!!!!!


来我们先打开Unity新建一个UnlitShader,把里面关于FOG的先删除掉,我们先不考虑FOG

首先我们需要使用到两套UV,然后gv是我们用来画水滴的,我们想要更窄一些

  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float4 col = 0;


  4.                                 float2 aspect = float2(2, 1);

  5.                                 

  6.                                 float2 uv = i.uv*_Size*aspect;


  7.                                 float2 gv = frac(uv)-0.5;


  8.                                 col.rg = gv;


  9.                                 return col;

  10.                         }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
Frac函数的定义——可以简单理解为去除整数只保留小数

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
目前得到的结果

接下来我们要在每个格子中间画圆(水滴),做到这一步就需要用到length函数,因为我们需要控制大小所以我们还要用到smoothstep函数,然后我们注意一点,因为我们在前面给uv乘了aspect,所以我们需要在gv除以aspect这样我们才能得到一个正圆而不是一个椭圆。

然后我们为了方便查看,我们加上一段,对比gv的x和y返回一个(1,0,0,0)也就是红色

这个很好理解我们之前给gv-0.5,所以现在gv是(-0.5.0.5)最大的值只有0.5。

  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float4 col = 0;


  4.                                 float2 aspect = float2(2, 1);


  5.                                 float2 uv = i.uv*_Size*aspect;

  6.                                 float2 gv = frac(uv)-0.5;


  7.                         //        注意给gv除以aspect,否则会得到一个椭圆

  8.                                 float drop = smoothstep(0.05,0.03,length(gv/aspect));


  9.                                 col += drop;

  10.                         //        col.rg = gv;

  11.                                 

  12.                         //  为了观察方便制作线条

  13.                                 if (gv.x > 0.48 || gv.y > 0.49) {

  14.                                         return float4 (1, 0, 0, 0);

  15.                                 }

  16.                                 return col;

  17.                         }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
目前得到的结果

我们现在就需要让这个点动起来了,首先我们需要用到Time这个是Unity给的,我们直接用就好了,然后我们用sin函数做循环,但是单纯的sin满足不了我们的要求,我们需要一个快速下落缓慢回来的动画,所以我们可以去找一条满足的条件的函数曲线(推荐网站:

https://www.desmos.com/calculator

非常好用,自动生成曲线,只需要输入数值,不懂就瞎乘嘛只要能得到想要曲线就好)

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
-sin(x+sin(x+sin(x)0.5))

  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float t = _Time.y;

  4.                                 float4 col = 0;


  5.                                 float2 aspect = float2(2, 1);

  6.         

  7.                                 float2 uv = i.uv*_Size*aspect;

  8.                                 float2 gv = frac(uv)-0.5;


  9.                                 float x = 0;

  10.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;

  11.                         

  12.                         //  控制gv.y来改变圆的位置

  13.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  14.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  15.                                 col += drop;

  16.                         //        col.rg = gv;

  17.                                 

  18.                         //  为了观察方便制作线条方便理解

  19.                                 if (gv.x > 0.48 || gv.y > 0.49) {


  20.                                         return float4 (1, 0, 0, 0);

  21.                                 }


  22.                                 return col;

  23.                         }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
目前得到的动画

现在我们已经有了一个水滴,我们添加一个拖尾(复制drop就可以了)
  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float t = _Time.y;

  4.                                 float4 col = 0;


  5.                                 float2 aspect = float2(2, 1);


  6.                         

  7.                                 float2 uv = i.uv*_Size*aspect;

  8.                                 float2 gv = frac(uv)-0.5;


  9.                                 float x = 0;

  10.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;

  11.                         

  12.                         //  控制gv.y来改变圆的位置

  13.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  14.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  15.                

  16.                                 float2 dropTrailPos = (gv - float2(x, 0)) / aspect;

  17.                         //      这里我们希望生成多个水珠拖尾所以我们把dropTrailPos.y乘8然后frac

  18.                         //        还是一样因为之前给dropTrailPos.y乘于了8所以我们需要除以8

  19.                         //        然后-0.03是因为我们得到的是一个半圆

  20.                                 dropTrailPos.y = (frac(dropTrailPos.y * 8)/8)-0.03;

  21.                                 float dropTrail = smoothstep(0.03, 0.02, length(dropTrailPos));


  22.                                 col += drop;

  23.                                 col += dropTrail;


  24.                         //  为了观察方便制作线条方便理解

  25.                                 if (gv.x > 0.48 || gv.y > 0.49) {


  26.                                         return float4 (1, 0, 0, 0);

  27.                                 }


  28.                                 return col;

  29.                         }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
目前得到的结果

现在我们需要做一个水珠的渐变,然后让uv也动起来,这样就可以做到循环运动

  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float t = _Time.y;

  4.                                 

  5.                             float4 col = 0;



  6.                                 float2 aspect = float2(2, 1);

  7.                                 float2 uv = i.uv*_Size*aspect;

  8.                         //  控制uv运动配合水滴下落

  9.                                 uv.y += t * 0.25;

  10.                                 float2 gv = frac(uv)-0.5;


  11.                                 float x = 0;

  12.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;

  13.                         

  14.                         //  控制gv.y来改变圆的位置

  15.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  16.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  17.                

  18.                                 float2 dropTrailPos = (gv - float2(x, t * 0.25)) / aspect;

  19.                         //  这里我们为了生成多个水珠拖尾所以我们把dropTrailPos.y 乘8然后frac

  20.                         //        还是一样因为之前给dropTrailPos.y 乘于了8所以我们需要除以8

  21.                         //        然后-0.03是因为我们得到的是一个半圆

  22.                                 dropTrailPos.y = (frac(dropTrailPos.y  * 8)/8)-0.03;

  23.                                 float dropTrail = smoothstep(0.03, 0.02, length(dropTrailPos));

  24.                         

  25.                         //  y值在-0.45与0.45之间,然后我们的gv.v在0.5,dropPos.y=gv.y-y,建议输出结果查看下就明白了

  26.                                 dropTrail *= smoothstep(-0.05, 0.05, dropPos.y);

  27.                                 dropTrail *= smoothstep(0.5, y, gv.y);


  28.                                 col += drop;

  29.                                 col += dropTrail;


  30.                         //  为了观察方便制作线条方便理解

  31.                                 if (gv.x > 0.48 || gv.y > 0.49) {


  32.                                         return float4 (1, 0, 0, 0);

  33.                                 }


  34.                                 return col;

  35.                         }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】

之前我们用sin控制了水滴的y方向运动,现在我们现在给水滴加上x的运动

x方向的运动尽可能要多一些波动,更像是水滴的运动

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
sin(3x)sin(x)^6

  1. fixed4 frag (v2f i) : SV_Target

  2.                         {        

  3.                                 float t = _Time.y;


  4.                                 float4 col = 0;


  5.                                 float2 aspect = float2(2, 1);

  6.                                 float2 uv = i.uv*_Size*aspect;

  7.                         //  控制uv运动配合水滴下落

  8.                                 uv.y += t * 0.25;

  9.                                 float2 gv = frac(uv)-0.5;

  10.                         

  11.                         //  用这个w值来控制拉伸程度        

  12.                                 float w = i.uv.y *10;

  13.                         //  现在我们不能用t来控制了,因为我们需要雨滴进行拉伸,所以我们利用uv来控制

  14.                                 float x = sin(3*w)*pow(sin(w),6)*0.45;

  15.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;

  16.                         //  改变了水滴的形状,目前是gv.x(-0.5,0.5)相乘得到一个对称的值

  17.                                 y -= (gv.x-x)*(gv.x-x);

  18.                         

  19.                         //  控制gv.y来改变圆的位置

  20.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  21.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  22.                                 float2 dropTrailPos = (gv - float2(x,t * 0.25)) / aspect;

  23.                         //  这里我们为了生成多个水珠拖尾所以我们把dropTrailPos.y乘8然后frac

  24.                         //        还是一样因为之前给dropTrailPos.y乘于了8所以我们需要除以8

  25.                         //        然后-0.03是因为我们得到的是一个半圆

  26.                                 dropTrailPos.y = (frac(dropTrailPos.y * 8)/8)-0.03;

  27.                                 float dropTrail = smoothstep(0.03, 0.02, length(dropTrailPos));

  28.                         

  29.                         //  y值在-0.45与0.45之间,然后我们的gv.v在0.5,dropPos.y=gv.y-y,建议输出结果查看下就明白了

  30.                                 dropTrail *= smoothstep(-0.05, 0.05, dropPos.y);

  31.                                 dropTrail *= smoothstep(0.5, y, gv.y);



  32.                                 col += drop;

  33.                                 col += dropTrail;

  34.                                 

  35.                         //  为了观察方便制作线条方便理解

  36.                                 if (gv.x > 0.48 || gv.y > 0.49) {


  37.                                         return float4 (1, 0, 0, 0);

  38.                                 }


  39.                                 return col;

  40. }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】

现在我们加入noise,让雨滴随机运动。

  1. //noise函数块

  2.                         float N21(float2 p){

  3.                                 p = frac(p*float2(123.34,345.45));

  4.                                 p +=dot( p,p+34.345 ) ;

  5.                                 return frac(p.x*p.y);

  6. }


  7.                         fixed4 frag (v2f i) : SV_Target

  8.                         {        

  9.                                 float t = _Time.y;

  10.                                 

  11.                                 float4 col = 0;


  12.                                 float2 aspect = float2(2, 1);

  13.                                 float2 uv = i.uv*_Size*aspect;

  14.                         //  控制uv运动配合水滴下落

  15.                                 uv.y += t * 0.25;

  16.                                 float2 gv = frac(uv)-0.5;

  17.                         //        id用来得到每格水滴

  18.                                 float2 id = floor(uv);

  19.                         

  20.                         //  得到每一格0或者1的随机值

  21.                                 float n =N21(id);

  22.                         //  用t+上现在每格水滴的系数,达到每格的时间都不一样

  23.                                 t+= n*5.345;


  24.                         //  用这个w值来控制拉伸程度        

  25.                                 float w = i.uv.y *10;


  26.                         //  我们把x也做一个随机的处理,使用n,得到-0.4,0.4的值

  27.                                 float x = (n-0.5)*0.8;

  28.                         //  0.4-abs( x )的值是控制幅度,然后乘以之前我们做的运动曲线

  29.                                 x += (0.4-abs(x))*sin(3*w)*pow(sin(w),6)*0.45;

  30.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;

  31.                         //  改变了水滴的形状,目前是gv.x(-0.5,0.5)相乘得到一个对称的值

  32.                                 y -= (gv.x-x)*(gv.x-x);

  33.                         


  34.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  35.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  36.                                 float2 dropTrailPos = (gv - float2(x, t*0.25)) / aspect;

  37.                                 dropTrailPos.y = (frac(dropTrailPos.y * 8)/8)-0.03;

  38.                                 float dropTrail = smoothstep(0.03, 0.02, length(dropTrailPos));

  39.                         

  40.                                 dropTrail *= smoothstep(-0.05, 0.05, dropPos.y);

  41.                                 dropTrail *= smoothstep(0.5, y, gv.y);



  42.                                 col += drop;

  43.                                 col += dropTrail;


  44.                         //  为了观察方便制作线条方便理解

  45.                                 if (gv.x > 0.48 || gv.y > 0.49) {


  46.                                         return float4 (1, 0, 0, 0);

  47.                                 }

  48.                                 return col;

  49.              }

复制代码



被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】

现在我们可以做最后一步了,在现在的效果下,添加一个直线的拖尾,然后加上图片,用目前的drop+dropTrail改变图片的UV就可以达到水滴折射的效果了

被甩后一个人打车看着窗外下大雨之雨滴玻璃shader【P1】
实在没办法,我只能拿我老婆的照片来用

  1. Shader "Billy/RainGlass_OP"

  2. {

  3.         Properties

  4.         {

  5.                 _MainTex ("Texture", 2D) = "white" {}

  6.                 _Size("Size",Float)= 1

  7.                 _Distortion("Distortion",range(0,1))=1

  8.         }

  9.         SubShader

  10.         {

  11.                 Tags { "RenderType"="Opaque" }

  12.                 LOD 100


  13.                 Pass

  14.                 {

  15.                         CGPROGRAM

  16.                         #pragma vertex vert

  17.                         #pragma fragment frag

  18.                         #include "UnityCG.cginc"


  19.                         struct appdata

  20.                         {

  21.                                 float4 vertex : POSITION;

  22.                                 float2 uv : TEXCOORD0;

  23.                         };


  24.                         struct v2f

  25.                         {

  26.                                 float2 uv : TEXCOORD0;

  27.                                 UNITY_FOG_COORDS(1)

  28.                                 float4 vertex : SV_POSITION;

  29.                         };


  30.                         sampler2D _MainTex;

  31.                         float4 _MainTex_ST;

  32.                         float _Size;

  33.             float _Distortion;

  34.                         

  35.                         v2f vert (appdata v)

  36.                         {

  37.                                 v2f o;

  38.                                 o.vertex = UnityObjectToClipPos(v.vertex);

  39.                                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);

  40.                                 return o;

  41.                         }

  42.                         


  43.                         float N21(float2 p){

  44.                                 p = frac(p*float2(123.34,345.45));

  45.                                 p +=dot( p,p+34.345 ) ;

  46.                                 return frac(p.x*p.y);

  47. }


  48.                         fixed4 frag (v2f i) : SV_Target

  49.                         {        

  50.                                 float t = fmod(_Time.y,7200);

  51.                                 float4 col =0;

  52.                                 float2 aspect = float2(2, 1);

  53.                                 float2 uv = i.uv*_Size*aspect;


  54.                                 uv.y += t * 0.25;

  55.                                 float2 gv = frac(uv)-0.5;

  56.                                 float2 id = floor(uv);

  57.                         


  58.                                 float n =N21(id);


  59.                                 t+= n*6.28631;



  60.                                 float w = i.uv.y *10;


  61.                                 float x = (n-0.5)*0.8;


  62.                                 x += (0.4-abs(x))*sin(3*w)*pow(sin(w),6)*0.45;

  63.                                 float y =-sin(t+sin(t+sin(t)*0.5))*0.45;


  64.                                 y -= (gv.x-x)*(gv.x-x);

  65.                         


  66.                                 float2 dropPos =(gv - float2(x, y))/aspect;

  67.                                 float drop = smoothstep(0.05,0.03,length(dropPos));


  68.                

  69.                                 float2 dropTrailPos = (gv - float2(x, t*0.25)) / aspect;

  70.                                 dropTrailPos.y = (frac(dropTrailPos.y* 8)/8)-0.03;

  71.                                 float dropTrail = smoothstep(0.03, 0.02, length(dropTrailPos));

  72.                                 float fogTrail = smoothstep(-0.05, 0.05, dropPos.y);

  73.                                 fogTrail *= smoothstep(0.5, y, gv.y);

  74.                                 dropTrail *= fogTrail;


  75.                                 fogTrail *= smoothstep(0.05,0.04,abs(dropPos.x));


  76.                                 col += fogTrail*0.5;

  77.                                 col += dropTrail;

  78.                                 col += drop;


  79.                                 

  80.                                 float2 offs = drop*dropPos+dropTrail*dropTrailPos;

  81.                                 col = tex2D(_MainTex,i.uv+offs*_Distortion);

  82.                                 return col;

  83.                         }

  84.                         ENDCG

  85.                 }

  86.         }

  87. }

复制代码




其实写完,这一部分先写到这,其实写完发现可能用shaderforge解释会更加方便和直观,下一部分会,贴上shaderforge的制作流程,会添加多层水滴和模糊镜面效果,如果有没看懂的留意下部分,用shaderforge试试就懂了。

记住保持一颗失恋的心,你会做的更好。

加油,骚年!

码字真不容易........

没有标签
确定
评论(1)
松上鹤唳
牛牛
回复
1420天前
没有更多啦~