unity 手机 模糊效果_Unity实现只狼弹反后处理效果

v2-98abbd816028fe2f4cd79eec73becff3_1440w.jpg?source=172ae18b

简介

今天是只狼发售一周年,作为去年的goty,只狼最核心的系统莫过于弹反,笔者去年也是和弦一郎大战几百回合,通关之后很想实现以下弹反瞬间的效果。

最终实现效果如下:

v2-b6150438ef22f04dd9519a423b8c6440.jpg
Unity实现只狼弹反后处理效果https://www.zhihu.com/video/1225108803152539648

笔者不是专业技美,如有问题,欢迎指出。

实现思路

首先仔细观察一下只狼在弹反的瞬间是怎么一个过程

首先是,受到攻击的瞬间,这一瞬间,产生了火花,并从弹反中心扩散出了一道模糊波纹,特效大小占据屏幕接近一半

v2-4c27ebba1fc0760b20348d67f4575f55_b.jpg

接着逐渐开始消散,火花熄灭,周边部分出现明显径向模糊效果

v2-583df7ef0d76504e5a5d7dff22862b3a_b.jpg

最后,中心开始逐渐清晰,到屏幕边缘的地方就基本消失了

v2-4163490aa61ea645bc65971ffae39e7c_b.jpg

总结起来就是从中心点开始,随着时间逐渐扩散

v2-0fe69675a3ade0321ea6d0fe27f7c09e_b.jpg

设计流程

特效部分我不是很擅长,所以就网上找了一个现成的卡通特效,我们这次就着重看一下后处理的部分。

径向模糊

首先我们实现一个由内到外扩张的一个整体径向模糊,方式也比较简单,先获取到弹反的中心点BlurCenter,然后在fragment阶段各个像素和他计算相对位置获得方向,对方向上的点采样取平均就可以了,核心代码如下:

fixed4 frag (v2f i) : SV_Target
{
    //这里是为了让扩散为圆形而不是屏幕的比例,_Aspect是屏幕的宽高比
    float2 p=i.uv*float2(_Aspect,1);
    float2 dir =normalize(p-_BlurCenter);
    dir*=_MainTex_TexelSize.xy;
    //对方向上的点采样取平均
    fixed4 col =tex2D(_MainTex,i.uv-dir*1) ;
    col +=tex2D(_MainTex,i.uv-dir*2) ;
    col +=tex2D(_MainTex,i.uv-dir*3) ;
    col +=tex2D(_MainTex,i.uv-dir*5) ;
    col +=tex2D(_MainTex,i.uv-dir*8) ;
    col +=tex2D(_MainTex,i.uv+dir*1) ;
    col +=tex2D(_MainTex,i.uv+dir*2) ;
    col +=tex2D(_MainTex,i.uv+dir*3) ;
    col +=tex2D(_MainTex,i.uv+dir*5) ;
    col +=tex2D(_MainTex,i.uv+dir*8) ;
    col *=0.1;

    return col;
}

此时我们应用在unity中,效果如下:

v2-737e9898b8a150707c22b246c9b1fba7_b.jpg

原图:

v2-1a89275aa1728ad0bc3ae23fe354144e_b.jpg

区别还是挺大的,很明显有径向模糊的效果,有那种感觉了。

径向模糊优化

上面的实现是逐像素的采样,而如果用户的电脑分辨率非常高的话,或者说用户的电脑配置不够,或者我们的平台是手机,那么我们就要做一定的优化。

我们可以先降低图片的分辨率,然后再采样,比如1080变成540,甚至270p,这样我们就能够大大降低gpu的负担,不过会多一层pass

270p压缩图:

v2-57700c77ac9ba3e87595f834fb443e07_b.jpg

270p+径向模糊:

v2-57096ea387ca2685d4b0f659534bb99f_b.jpg

540p+径向模糊:

v2-75e0227cf228f9f5ac6d4e16830129e6_b.jpg

注意:对应不同的像素密度我们也要控制采样范围

相关的cs部分如下:

private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
    RenderTexture rt1 = RenderTexture.GetTemporary(source.width >> downSampleFactor, source.height >> downSampleFactor, 0, source.format);
    RenderTexture rt2 = RenderTexture.GetTemporary(source.width >> downSampleFactor, source.height >> downSampleFactor, 0, source.format);
    Graphics.Blit(source, rt1);

    //使用降低分辨率的rt进行模糊:pass0
    Graphics.Blit(rt1, rt2, material, 0);

    //使用rt2和原始图像lerp:pass1
    material.SetTexture("_BlurTex", rt2);
    Graphics.Blit(source, destination, material, 1);

    //释放RT
    RenderTexture.ReleaseTemporary(rt1);
    RenderTexture.ReleaseTemporary(rt2);
}

波纹扩散

为了做更好的过渡以及定制化,我们使用unity的curve来实现当前径向贴图的采样程度

v2-aa66b8f07b9ef97cc70a6b5dc30d3b42_b.jpg

同时,为了更好的性能,我们应该把这部分计算放在gpu部分,可以采用生成贴图的方法:

private void Start()
{
    //初始化振幅贴图(也就是把waveform曲线初始化到gradTexture上面)
    gradTexture = new Texture2D(1024, 1, TextureFormat.Alpha8, false);
    gradTexture.wrapMode = TextureWrapMode.Clamp;
    gradTexture.filterMode = FilterMode.Bilinear;
    for (var i = 0; i < gradTexture.width; i++)
    {
        var x = 1.0f / gradTexture.width * i;
        var a = curve.Evaluate(x);
        gradTexture.SetPixel(i, 0, new Color(a, a, a, a));
    }
    gradTexture.Apply();

    //初始化material
    material = new Material(PointBlurShader);
    material.hideFlags = HideFlags.DontSave;
    material.SetTexture("_GradTex", gradTexture);
}

这样,shader部分就得到了当前曲线上所有的数据,存储在了_GradTex中。

最终,我们在frag部分完成当前的采样,相关代码如下

//计算当前像素点的采样程度,_Timer为特效产生开始的计时
float GetBlurPercent(float2 pos){
    //计算当前时间以及像素为主下,对应的曲线横坐标t
    float t=_Timer-length(pos-_BlurCenter)/_BlurSpeed;
    //如果要让这个波纹的宽度变大可以调整BlurCircleRadius
    t*=1/_BlurCircleRadius;
    //获取对应值
    return tex2D(_GradTex,float2(t,0)).a;
}

fixed4 frag_mix (v2f_lerp i) : SV_Target{
    fixed4 rawCol = tex2D(_MainTex, i.uv1);
    fixed4 blurCol = tex2D(_BlurTex, i.uv2);
    fixed4 col = lerp(rawCol,blurCol,_BlurStrength
                      //获取当前像素点在曲线上的值
                      *GetBlurPercent(i.uv1*float2(_Aspect,1))
                      //范围限制,调整BlurRange可以控制波的大小
                      *min(_BlurRange/length(i.uv1*float2(_Aspect,1)-_BlurCenter),1));

    return col;
}

特效

后处理的部分就基本完成了,然后我们加上一些lensflare和particle,我们的效果就完成了~调的参数有点高,狼都看不清了2333

v2-a897272a8a4f9e453b54c099ac9722c7_b.jpg

应用

我观察了很多游戏,尤其是动作游戏,在径向模糊这块几乎是一个必备的要素,而且反馈感非常高,可以把打击感提高好几个层次。

v2-545f5deaf2b01b0e715bdced3f97f733_b.jpg
怪物猎人

v2-ceb64a1397910a68d1a7039d6a2222b4_b.jpg
生化危机

v2-0da373e82cdcd134c3c867f3380ec6e6_b.jpg
鬼泣

要问为啥都是卡婊的游戏,我也不知道。

结语

项目原工程地址:https://github.com/cyclons/SekiroBlock

相比于写游戏逻辑,写shader还是非常享受的一个过程,编译快,反馈强,唯一比较难受的还是ide吧。

感谢观看!

参考文章

Unity Shader-后处理:径向模糊效果

unity用shader来实现2D涟漪/水波纹特效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值