UnityShader实例16:屏幕特效之径向模糊(Radial Blur)

径向模糊(Radial Blur)


概述


       径向模糊,是一种从中心向外呈幅射状的逐渐模糊的效果(如下图),在图形处理软件photoshop里面也有这个模糊滤镜。而在游戏中常常用来模拟一些动感的效果,如鬼泣4中的场景切换特效,和一些技能打击特效;赛车游戏也尝用来模拟动感模糊,如狂野飙车,极品飞车等。本例将实现一个类似效果适用于手机平台的径向模糊效果,将开放模糊强度以及模糊范围两个参数调整模糊效果。





实现原理及流程


       径向模糊和高斯模糊等其他模糊效果一样,原像素都要周围附近的像素的颜色值共同影响。如高斯模糊就是将原像素四周像素的颜色加权求和作为原像素的颜色以达到模糊的目的,而径向模糊的特点是从某个像素为中心向外辐射状扩散,因此需要采样的像素在原像素和中间点像素的连线上,不同连线上的点不会相互影响。简单的说,就是像素的颜色是由该像素的点与中心点之间连线上进行采样(如图),然后求将这些采样点颜色的加权平均和作为该像素的颜色。根据径向模糊的特性,离目标点越近采样点越密集,反之亦然。

       由此我们可以大概确定下径向模糊实现的流程:
  •        第一步:确定径向模糊的中心点,通常取图像的正中心点、
  •        第二步:计算采样像素与中心点的距离,根据距离确定偏移程度,即离中心点越远,偏移量越大。
  •        第三步:将采样点的颜色值做加权求和,本例使用平均求和。
  •        第四步:将前面的结果与原图像做一个lerp差值合成


基于移动平台的优化


       从径向模糊的原理可知,由于需要获知每个像素点距离中心点的距离,并且根据采样点的距离采样偏移不一样,,因此不能像高斯模糊那样在vert函数里面进行uv整理偏移采样,只能在frag函数中逐像素计算,因此当分辨率越大,计算量成几何倍数增长。对于一些高分辨率的设备,比如ipad4,iphone6等,如果直接采样的话,则可能导致帧率下降得很厉害的结果,甚至还不如iphone5的帧率 。
       没法从vert函数那里优化,那么只能降低frag函数部分的采样,最简单的方法就是降低屏幕图像的分辨率。但付出的代价就是需要两个缓存来存贮屏幕图像,增加2个drawcall,不过还是值得的,真机测试帧率提高了不少。流程也因此也得改一下,得分两个pass分别处理模糊计算(降低分辨率计算)和lerp差值合成(恢复到正常分辨率)。这样保证最后输出的结果还是原来的分辨率,清晰部分不变,而模糊部分质量稍微有下降,但实际效果还是可以接受的。



shader实现


       这里我只放出关键代码,需要完整代码可以点文章后面链接下载。 
       根据需求我们需要从C#脚本传递两个参数_SampleDist和_SampleStrength分别控制模糊强度和模糊范围:
		uniform float _SampleDist;
		uniform float _SampleStrength;

       从优化流程可知,我们需要两个pass分别处理模糊计算和lerp差值合成,先处理模糊计算,主要计算在frag函数中完成。需要注意的是,从C#传递过来的图像是已经降低过分辨率的,关键代码如下:
		fixed4 fragRadialBlur (v2f i) : COLOR
		{
      //计算辐射中心点位置
			fixed2 dir = 0.5-i.texcoord;
     //计算取样像素点到中心点距离
			fixed dist = length(dir);
			dir /= dist;
			dir *= _SampleDist;

			fixed4 sum = tex2D(_MainTex, i.texcoord - dir*0.01);
			sum += tex2D(_MainTex, i.texcoord - dir*0.02);
			sum += tex2D(_MainTex, i.texcoord - dir*0.03);
			sum += tex2D(_MainTex, i.texcoord - dir*0.05);
			sum += tex2D(_MainTex, i.texcoord - dir*0.08);
			sum += tex2D(_MainTex, i.texcoord + dir*0.01);
			sum += tex2D(_MainTex, i.texcoord + dir*0.02);
			sum += tex2D(_MainTex, i.texcoord + dir*0.03);
			sum += tex2D(_MainTex, i.texcoord + dir*0.05);
			sum += tex2D(_MainTex, i.texcoord + dir*0.08);
			sum *= 0.1;
			
			return sum;
		}



       另外一个pass用上一个pass处理好的模糊结果与源图像做差值合成,其中_SampleStrength控制模糊的范围,这一步使用的是正常分辨率的计算。

		fixed4 fragCombine (v2f i) : COLOR
		{
			
			fixed dist = length(0.5-i.texcoord);
			fixed4  col = tex2D(_MainTex, i.texcoord);
			fixed4  blur = tex2D(_BlurTex, i.texcoord);
			col=lerp(col, blur,saturate(_SampleStrength*dist));
			return col;
		}



C#脚本

       C#脚本比较简单,主要是将屏幕图像降低分辨率传给shader处理,这里只放出关键代码,需要完整代码请到文章后面的下载链接下载。

	void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture)
	{	
		#if UNITY_EDITOR
			FindShaders ();
			CheckSupport ();
			CreateMaterials ();	
		#endif

		if(SampleDist != 0 && SampleStrength != 0){

			int rtW = sourceTexture.width/8;
	        int rtH = sourceTexture.height/8;


	        RadialBlurMaterial.SetFloat ("_SampleDist", SampleDist);
	        RadialBlurMaterial.SetFloat ("_SampleStrength", SampleStrength);	


	        RenderTexture rtTempA = RenderTexture.GetTemporary (rtW, rtH, 0,RenderTextureFormat.Default);
            rtTempA.filterMode = FilterMode.Bilinear;

            Graphics.Blit (sourceTexture, rtTempA);

            RenderTexture rtTempB = RenderTexture.GetTemporary (rtW, rtH, 0,RenderTextureFormat.Default);
            rtTempB.filterMode = FilterMode.Bilinear;

            Graphics.Blit (rtTempA, rtTempB, RadialBlurMaterial,0);

            RadialBlurMaterial.SetTexture ("_BlurTex", rtTempB);
       		Graphics.Blit (sourceTexture, destTexture, RadialBlurMaterial,1);

            RenderTexture.ReleaseTemporary(rtTempA);
            RenderTexture.ReleaseTemporary(rtTempB);
 
		}

		else{
			Graphics.Blit(sourceTexture, destTexture);
			
		}
		


本例实现效果如图




总结

       本例径向模糊特效是为移动平台服务的,主要的优化也是有C#脚本来实现,在这里我们将屏幕图像长宽分别缩小为原来的8分之一,那么计算量至少减少为原来64分之一。以每个点需要10次采样计算的话,节省的计算量是惊人的。在实际应用中,我们可以根据机型或者分辨率,来控制分辨率缩小的比率,在美术效果和计算效率取到一个比较合理的平衡,而不是本例的一刀切,不管分辨率大小一律除以8,可能导致一些分辨率比较低的机型效果缩水严重。



下载链接

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Unity径向菜单是一种常见的用户界面元素,用于提供快速且方便的菜单选项选择。它通常位于屏幕中心或指针周围,以圆形或弧形的形式展现。 径向菜单的主要特点是它的交互方式。当玩家点击菜单触发器,菜单将以指针为中心展开,并在指针周围显示各种选项。这种设计使玩家能够直观地选择他们想要的选项,而无需在屏幕不同区域之间移动。除了鼠标点击外,它还可以适应触摸和手势输入。 在Unity中创建径向菜单相对简单。可以使用UGUI中的按钮和画布元素来实现。首先需要一个容纳按钮的父物体,然后将按钮对象放在该父物体下,并相对于父物体进行定位。然后,将按钮的功能与相应的脚本或方法关联起来,以实现用户点击按钮后的特定操作。 径向菜单的优点之一是它提供了更大的输入空间,使得用户可以在快速快捷选项之间进行选择,而无需切换到不同的屏幕区域。它还能够提供更多菜单选项,使得用户可以在不同的情况下进行操作,提供了更灵活和高效的操作方式。 不过,径向菜单也有一些限制。由于菜单选项的圆形排列,如果菜单选项过多,可能会导致按钮重叠或难以触摸到。此外,菜单选项的布局和显示需要合理设计,以确保用户能够轻松理解和选择所需的选项。 总的来说,Unity径向菜单是一种方便且直观的用户界面元素,可以帮助玩家快速选择他们想要的选项。通过合理设计和布局,径向菜单在游戏和应用程序中提供了更好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值