Unity Shader 雨天效果

作者: 烂醉花间dlitf | 来源:发表于2020-12-14 23:39 被阅读0次

教程原链接

https://zhuanlan.zhihu.com/p/182459720
https://deepspacebanana.github.io/deepspacebanana.github.io/blog/shader/art/unreal%20engine/Rainy-Surface-Shader-Part-1

涟漪效果

fixed4 frag (v2f i) : SV_Target
{
    float t = frac(_Time.y * _Speed); 
    fixed3 col = fixed3(t,t,t);
    UNITY_APPLY_FOG(i.fogCoord, col);
    return fixed4(col,1);
}

这样可以实现这样的一个渐变效果:


折线图
效果图

然后思考一下我们怎么做成这样的效果:


雨滴初现

我们可以看到这个点点的贴图,作者是放在了一张贴图的红色通道里面:


baseColor

先按下面的写法提出红色通道的图:

fixed3 texColor = tex2D(_MainTex,i.uv);![4.gif](https://img.haomeiwen.com/i17546328/23f30d159431988e.gif?imageMogr2/auto-orient/strip)

col = fixed3(texColor.r,texColor.r,texColor.r);
红色通道
Unity 预览图片

可以看到代码提出来的红色通道失真非常严重(目前不知道为什么,开了抗锯齿和双线性插值都不行),但目前不影响我们继续,合理想象一下,我们需要白点从 0 - 1,然后骤降到 0。所以按下面的写法就完成了:

fixed4 frag (v2f i) : SV_Target
{
    float t = 1-frac(_Time.y * _Speed); 
    fixed3 col = fixed3(t,t,t);
    fixed3 texColor = tex2D(_MainTex,i.uv);
    col = fixed3(texColor.r,texColor.r,texColor.r)-t;
    UNITY_APPLY_FOG(i.fogCoord, col);
    return fixed4(col,1);
}

可以看到效果好像是从每个圆中间逐渐向周围出现的,但其实这个是因为本身贴图的每个圆都是中间最白,逐渐变黑。此时此刻,黑色部分是从 0~-1(只是因为小于 0 的话,显示出来的还是黑色,所以看不出来而已,但需要记住黑色的 rgb 值也是有变化的),而白色小圆圈是从 0~1;此时想要做出这种效果,我们可以想到其实就是把黑白边界给做出来,那我们只要计算每个像素跟 0.05(这个大小可以自动调节,但不能太大,最后圆环的宽度应该是这个值的两倍)的距离就可以把边界用两条黑线给画出来。

fixed4 frag (v2f i) : SV_Target
{
    float t = 1-frac(_Time.y * _Speed); 
    fixed3 col = fixed3(t,t,t);
    fixed3 texColor = tex2D(_MainTex,i.uv);
    float dis = saturate(distance(texColor.r - t,0.05)/0.05);
    col = fixed3(dis,dis,dis);
    UNITY_APPLY_FOG(i.fogCoord, col);
    return fixed4(col,1);
}
黑色圆环

因为外面也在闪烁,所以不是很清楚的看出来,黑色圆环其实是中间两个连着很近的黑线,然后逐渐向两边减淡的样子。可以思考一下,除了小圆点之外的为什么也开始闪烁了,其实它原本应该是从 -1~0 的状态,计算了距离之后,就是从 0.95~0.05 的状态了,我们怎么让他保持不变呢,可以发现他的最小值也是 0.05,那只要用它去除 0.05,得到的值就是 1-19,而大于 1 的部分显示为颜色都是白色。再验证一下黑色圆环的部分是否会受到影响,它的范围应该是 0-0.05,那么除下来结果为 0 ,没有问题。再验证一下小圈圈内的部分是否会受到影响,它的范围是 0.05-0.95,也没有问题。ok,最后用 saturate 把值都限制在 0-1 就 ok 了(不写这个也没关系)

涟漪初现
现在就是只有黑白,没有过渡的小圆圈的涟漪效果了。看起来有点密,还有点脏(暂时不知道为什么,既然有的小圆圈是不脏的,那应该是贴图的问题吧,就是 0-1 的过渡不是线性的话就会出现脏脏的效果)。
现在再复制一份,然后让 uv 和时间都交错一点,顺便给它换成黑底的,话说程序员是不是对深色都比较情有独钟, 前 leader 就说过我能不能把 mac 初始的白色终端换个颜色。
交错
交错效果图
fixed4 frag (v2f i) : SV_Target
{
    float lerp_t = frac(_Time.y * _Speed); 
    float t = 1 - lerp_t; 
    float t2 = 1 - frac((_Time.y) * _Speed + 0.5); // 时间偏移一点点
    fixed3 col = fixed3(t,t,t);
    fixed3 col2 = fixed3(t,t,t);
    fixed3 texColor = tex2D(_MainTex,i.uv);
    fixed3 texColor2 = tex2D(_MainTex,i.uv + float2(0.5,0.5)); // uv 偏移一点点
    float dis = saturate(1-distance(texColor.r - t,0.05)/0.05);
    float dis2 = saturate(1-distance(texColor2.r - t2,0.05)/0.05);
    col = fixed3(dis,dis,dis);
    col2 = fixed3(dis2,dis2,dis2);
    fixed3 finalCol = lerp(col,col2,lerp_t); // 1的圈圈越大越偏向2,这样就有涟漪越大,越淡的效果了
    UNITY_APPLY_FOG(i.fogCoord, finalCol);
    return fixed4(finalCol,1);
}

这样乍一看没什么问题,但其实第二张图从 0.5 会有一个骤变,所以思考一下,图 1 和图 2 相差了 0.5s 的时间,,但还是要保证对于每个图来说,都是要从 1-0,画个简单的图就会发现这是不可能的,因为在图 1 在 0.5 的时候要求图 2 是1。那退而求其次,对每一个图来说都要从 0-1-0。像下面这个图一样:


非常丑的示意图

会发现正好满足我们需求,对于图 1 和图 2 的每一个周期来说都是从 0-1-0,代码如下:

fixed4 frag (v2f i) : SV_Target
{
    float lerp_t = frac(_Time.y * _Speed); 
    float t = 1 - lerp_t; 
    float t2 = 1 - frac((_Time.y) * _Speed + 0.5); // 时间偏移一点点
    fixed3 col = fixed3(t,t,t);
    fixed3 col2 = fixed3(t,t,t);
    fixed3 texColor = tex2D(_MainTex,i.uv);
    fixed3 texColor2 = tex2D(_MainTex,i.uv + float2(0.5,0.5)); // uv 偏移一点点
    float dis = saturate(1-distance(texColor.r - t,0.05)/0.05);
    float dis2 = saturate(1-distance(texColor2.r - t2,0.05)/0.05);
    col = fixed3(dis,dis,dis);
    col2 = fixed3(dis2,dis2,dis2);
    float lerp_t2 = sin(lerp_t * 3.14159); // 把 [0,1] 映射到 [0,3.14159] 得到 sin 的半个周期,所以并不需要 abs
    fixed3 finalCol = lerp(col2,col,lerp_t2);
    UNITY_APPLY_FOG(i.fogCoord, finalCol);
    return fixed4(finalCol,1);
}

顺便说一下之前觉得雨点很脏,很密集的问题,是因为雨点确实很多,所以在面板上将大小设置为 0.5 就好了,只使用四分之一的大小。


Inspector 面板
效果图

相关文章

网友评论

    本文标题:Unity Shader 雨天效果

    本文链接:https://www.haomeiwen.com/subject/prgpgktx.html