水滴流动特效(一)
Posted on
前言
水滴流动特效是开放世界游戏非常常见的效果,在shadertoy看到一个没有使用任何贴图做的效果:
https://www.shadertoy.com/view/ltffzl
这个作者在Youtube上分享了他制作这个效果的过程
https://www.youtube.com/watch?v=EBrAdahFtuo
这里就将他制作的过程整理成图文教程
水滴圆点的制作
1 2 3 4 5 6 7 8
| float4 col = 0; float2 uv = inputUV * _Size; //_Size控制tilling float2 gv = frac(uv)-.5; float2 dropPos = gv; float drop = smoothstep(.05, .03, length(dropPos)); if(gv.x > .48 || gv.y > .49) col = float4(1,0,0,1); //绘制红线 col += drop; retun col;
|
由于正方形的话水滴间距离有点太大,所以增加aspect参数,把每个区域变成长方形
1 2 3 4 5 6
| float2 aspect = float2(2, 1); float2 uv = i.uv * _Size * aspect; //_Size控制tilling float2 gv = frac(uv)-.5; float2 dropPos = gv / aspect; float drop = smoothstep(.05, .03, length(dropPos)); if(gv.x > .48 || gv.y > .49) col = float4(1,0,0,1); //绘制红线
|
水滴的移动
1 2
| t = _Time.y; uv.y += t * .25;
|
接着希望给水滴小圆点的移动做一些offset,使得它下落先慢后快
1 2 3 4
| float x = 0; float y = -sin(t+sin(t+sin(t)*.5)) * .45; //不乘0.45水滴会是半个 float2 dropPos = (gv - float2(x,y))/aspect; float drop = smoothstep(.05, .03, length(dropPos));
|
水滴的轨迹
小水珠
因为水滴在物体表面下落时会在轨迹上留下小水珠,所以要在水滴后面加上小水珠,这些小水珠位置是不动的,所以要加一个向后倒退的速度来抵消现在的0.25t的速度
1 2 3 4 5 6 7 8
| float2 dropPos = (gv - float2(x,y))/aspect; float drop = S(.05, .03, length(dropPos)); float2 trailPos = (gv - float2(x,t * .25))/aspect; trailPos.y = (frac(trailPos.y * 8)-.5)/8; float trail = S(.03, .01, length(trailPos)); col += trail; col += drop;
|
拖尾
除了小水珠之外,还有比较薄的一层水质,这个区域可以来作为许多东西的判定,比如水滴划过的地方在玻璃等表面会刷掉气雾小水珠,在原来干燥的表面划过的地方会有潮湿的质感
1 2 3
| // 先在水滴后部加上 float fogTrail = S(-.05, .05, dropPos.y); col += fogTrail * .5;
|
1 2 3 4
| // 加上逐渐消失的效果 float fogTrail = S(-.05, .05, dropPos.y); fogTrail *= S(.5, y, gv.y); col += fogTrail * .5;
|
1 2 3 4 5 6 7 8 9
| // 用这个fogtrail的结果乘到之前的trail上,使小水滴也逐渐消失,并把宽度限定在水滴的宽度 float fogTrail = S(-.05, .05, dropPos.y); fogTrail *= S(.5, y, gv.y); trail *= fogTrail; fogTrail *= S(.05, .04, abs(dropPos.x)); col += fogTrail * .5; col += fogTrail * .5; col += trail; col += drop;
|
水滴的横向扭动
1 2 3
| 这个就选一个自己认为合适的函数给x就行,这里使用: float w = i.uv.y * 10; float x = sin(3*w)*pow(sin(w), 6)*.45;
|
增加随机性
显然这些水滴不能这么整齐,这里使用一个随机函数,可以把一个float2随机到(0, 1)的float
1 2 3 4 5
| float N21(float2 p){ p = frac(p*float2(123.34, 345.45)); p += dot(p, p+34.345); return frac(p.x*p.y); }
|
输入uv就是这样的结果
1 2 3 4
| // 给每个长方形区域一个随机的值 float2 id = floor(uv); float n = N21(id); return n;
|
return n就是这个结果,每个长方形区域有一个随机的(0, 1)的值
利用这个值就可以让每个雨滴有一些自己的变化
1 2 3 4 5
| //给之前x轴上的变化加一些随机性 float w = inputUV.y * 10; //float x = sin(3*w)*pow(sin(w), 6)*.45; float x = (n - .5)*.8; x += (.4-abs(x)) * sin(3*w)*pow(sin(w), 6)*.45;
|
1 2
| //使不同雨滴有时差 t += n*6.2831;
|
使用水滴
水滴在物体表面上会有折射的效果,我们直接对贴图采样时的uv值做偏移也能达到类似的效果
1 2
| float2 offs = drop * dropPos + trail * trailPos; col = tex2D(_MainTex, i.uv + offs * _Distortion);
|
输出offset*10:
输出col: