写在前面
好久没有写shader了,最近项目中需要实现一个弹窗背景是模糊的游戏场景。大致效果如下:
看起来好像比较抽象!?我去找个好看的效果图。
原理
首先我们看一下图层结构:
bg是我们的需要模糊的游戏页面,target和message box是我们需要显示先模糊上层的。blurBg是我们的模糊层。
我们想实现这个效果最简单的方法就是让美术出一个透明模糊图即可,把这个图放在我们的模糊层。就完事了。事实好像是这样要简单很多哈...
糟了,转不回来了,我们来说原理....
原理其实很简单,我们需要先把当前屏幕所渲染的画面记录下来,存到一个贴图里,然后对这个图片做模糊。
获取当前屏幕颜色并记录下来,我们使用的是:
GrabPass {}
我们只是需要在subshader中声名一个这个pass块即可。它默认会把当前屏幕渲染画面存在一个叫“_GrabTexture”的贴图中。当然我们也可以自定义名字:
GrabPass{"_BackgroundTexture"}
我们获得了这张图然后开始做模糊,模糊我们都知道是使用卷积。但是个人认为模糊就是把我们需要模糊的图,像是复制几张相同的图片,然后再把几张图片按照一定的偏移量来摆设。这样就出现了模糊的效果,如果我们把偏移值放大一些,我们就可以看到我们卷积生成的几张图。几乘几的卷积就是几张图。可以看看源码:
这里的模糊算法我使用的是《Unity shader入门精要》里屏幕后处理高斯模糊里的算法。这里有一个优化点,就是我们可以把计算卷积点放在片元函数中。
差不多就这么多了吧~
2019年3月17日更新
在前段时间对该效果做出了一定的优化,其中优化的原因:
1.模糊效果并不能达到到美术的要求。
2.在使用模糊效果的时候背景会出现一定的偏移,影响体验。
之前使用的十字型的卷积来做处理,现在使用7x4的矩形。这样使的卷积偏移更加的平滑,效果也更加的好。
我试过9x9的矩阵,效果是跟上了但是还是会有一定的偏移,而且这样的转换颜色的消耗比7x4更加多一些。
具体代码:点这里
2019年8月2日更新
这里的GrabPass 采样pass块我们最好是自定义一个名字,这个样是可以达到一个优化的效果。
- GrabPass { } :截取当前屏幕到_GrabTexture的贴图上。在有多个使用该方式截图时会更加耗时。
- GrabPass { "TextureName" } :截取当前屏幕到_GrabTexture的贴图上。在有多个使用该方式只有第一个使用该方法的在每一帧渲调用。这个会更加高效。