Unity粒子特效优化实践

时间:2022-08-14 20:16:03

先记录一下,等有时间再好好整理一遍。

虽然对于移动平台来讲,一直不建议大量使用粒子特效,因为对CPU和GPU来讲,都是一个负担。但是现在粒子特效在策划那边需求特别大,也就没有办法。但是很无语的是,一个武器的绑定特效有7个drawcall,策划虽然安慰我们说全服不会有几个,但是最后事实肯定不是他们说的那样。

拿来做优化实例的粒子,有两个mesh+5个粒子发射器组成,5个粒子发射器中有3个billboard粒子,两个mesh粒子。其中一个billboard粒子和一个mesh粒子共用了一个材质。对于单一特效来说,7个drawcall,一个都没有batch掉。

然后我们将这个粒子复制10个,发现batch掉的特效只有billboard粒子,mesh粒子以及两个mesh物体都没有动态batch。

unity动态合批的规则比较苛刻,首先材质必须一致,其次顶点属性个数不超过900个,对于一个shader,如果包含了顶点位置,uv,顶点颜色三个属性的话,那么这个个数就只有300个。

对于billboard粒子来说,它基本上会符合上述的要求,因为billboard粒子抛弃了这些属性。但是对于mesh粒子来说, 基本上都是300个限制。

表面上的规则是这样的,但实际应用上的坑依然比较多。

首先是billboard粒子,即使是相同材质的粒子batch,也要保证这些batch的粒子在渲染队列中是连续的,否则不会batch,这就需要在粒子的render标签中设置sortlayer和orderinlayer来保证它的渲染顺序。但是手动调整render queue的弊端就是,如果一个粒子在世界中位置靠后但渲染队列中也很靠后,会把前面的粒子给遮挡中。因为对于半透明物体来讲,正确的渲染顺序是从后向前。

其次是mesh粒子,这个的坑点在于尝试了百八十遍依旧没有一次成功batch掉的经历。即使使用的mesh是一个quad,发射器发射的粒子很少,肉眼观察绝对不会超过300个顶点限制的粒子,复制多个出来,依旧不会batch。但是并没有在unity的官方doc中找到mesh粒子不会被动态batch掉的相关说明。所以这块到底真实情况如何我也不能保证。

不过特效中的两个单纯的mesh对象在复制多个的情况下直接static batch掉了。

 

然后就是一些其余的尝试,首先是合图,这也是unity的文档中动态合批时给出的建议,但是在粒子中并不试用,首先是billboard粒子没有uv,这使得合图后也不能通过uv将对应的纹理抠出来。其次是mesh粒子虽然有uv,可以进行合图,但是如上述所说,并不会动态合批,最终的结果只是减少了一个材质球而已。

上述的尝试算是没什么结果,接下来就更感人了。

尝试使用shader+脚本的方式来代替粒子效果。

首先,粒子系统功能有多强大不用说了,不可替代性也不用说了。但是对于一些简单的粒子效果,完全可以使用shader+脚本的方式来简单模拟。因此,我写了四个shader,分别是闪烁,扩散,旋转,序列帧播放四个shader来代替,以及计划billboard脚本和scale和rotation脚本(还没搞)。

用四个shader+quad的方式代替里几个粒子,然后打包到安卓平台监视性能。很悲惨的发现,性能消耗高了不少。原来的特效复制十个摆放在场景中,cpu的渲染大概在10ms+,drawcall在100以内。修改之后的效率是cpu渲染12ms左右,drawcall 110左右。简单的分析原因就是上面讲过的,首先是这些替代的quad以及剩余的billboard粒子因为渲染队列不连续不能动态batch,导致drawcall增加。不过从overdraw来看,gpu因为overdraw的降低性能得到了改善。因为大量粒子会导致overdraw增高,gpu需要大量重绘。

但是mesh的渲染队列调整只能在shader中修改queue,没有粒子修改起来那么方便,如果使用同个shader来制作不同的material,这也会导致渲染队列混乱,这就使得shader+脚本的原本美好的构想得不偿失了,同时还会给特效制作人员带来困难,所以到这里就暂时放弃了。