Unity

Unity 毛玻璃效果(UGUI)

最近想在UI中加入类似Win7的毛玻璃效果,将弹窗UI的背景虚化。实现的原理很简单,就是对UI的背景做一下Blur。在实现过程中,我尝试了两种方法:

1、直接Blur UI后面的图像。

这是网上很多文章提供的方法,也比较容易想到。可以直接用Shader控制UI 背景Panel上Image组件的渲染。

因为Unity 提供了GrabPass,可以在Shader中很方便的拿到Panel下面的图像,即_GrabTexture。

问题在于如何对_GrabTexture做Blur处理。如果使用普通的高斯模糊,效果并不理想,原因在于模糊半径太小了,导致模糊后的图像太清晰,玻璃“不够毛”。

我前面一篇分析Bloom效果的日志,提供了一种方法,先对图像做向下采样,然后再做模糊处理,这样做出来的模糊效果比较理想,但是无法通过一个Pass实现。而在Image控件上使用的Shader并不能自由的控制Pass,所以只能硬着头皮用一个Pass做大面积的模糊处理。所以我放弃了高斯模糊,而使用发现贴图扰动的方式做模糊处理。代码看起来很Low:

采用了36次采样,初步得到了一个比较理想的效果:

frosted_glass_1

但这种方法也有问题,就是如果Blur图像中存在UI、文字等棱角分明的部分,Blur效果就很差:

frosted_glass_2

所以最终还是放弃了这个比较简单的方案。

2、多Pass Blur

由于Unity的渲染机制,Pass与DrawCall无关,也就是说,多Pass的后渲染处理,只能放在摄像机上在屏幕空间上做,而不能单独控制单个GameObject的渲染。所以,只能借助摄像机进行。结合上一篇Bloom中的方法,要先把场景渲染结果做向下采样处理,处理成一张小图,然后再做Blur处理。

这里用了一个省力的做法,给摄像机提供一个很小的RenderTexture,自动完成向下采样。RT越小,Blur效果越理想,经过测试,我用了1/32屏幕长宽的RT,得到RT后,创建一个Sprite赋值给Image组件,然后再用Shader在Image渲染的时候做Blur处理。

shader如下:

这里发现了几个蛋疼的问题,

1、在OnEnable时,Screen的长宽获取的值是错误的,所以不能在那个时机取屏幕大小。

2、使用了降采样的图像后,在Image的Shader中,_MainTex_TexelSize 的值变成了(1,1,1,1),所以也用不了了。只能先写死一个比例,后面可以通过参数传到Shader中。

最后的结果还算理想:

frosted_glass_3

发表评论