粒子特效对于表现来说,至关重要,但对CPU和GPU来讲,是一个性能消耗的大户。以下记录一些针对移动端的优化方式。
限制同屏Max粒子数
数量尽可能少,推荐30-50个粒子系统,300-500个总粒子数。
面积占比
尽可能小,过大会影响像素填充率的效率。
贴图
- 降低分辨率
- 很小的粒子,考虑去掉Alpha通道
PS:透明将产生大量的Overdraw。一般来说,Overdraw可能是粒子特效消耗性能的最大因素。
设计复杂度
避免粒子发射器之间的嵌套迭代,控制在1-2层。
Shader
发布移动端,Shader用Mobile平台的。
光照计算复杂度
- 不接收阴影,不产生阴影
- 去掉灯光相关设置
Render Mode
Billboard优先于Mesh类型。
如果是Mesh类型:
- DCC软件合并Mesh
- 勾选Unity的Static选项
- 如果骨骼,骨骼数量少于30
- 建议同一时间不超过5个,单个顶点不超过500
- GPU实例化(Enable Mesh GPU Instancing)
限制发射速率 Loop Duration
如果周期很小,就会不断的生成发射器,对CPU也有一定影响。
剔除&可见性更新
可以在Unity的剔除系统中嵌入CullingGroup ,这样就可以使用边界球创建剔除区域。
当该区域变为可见或不可见时会发送一条通知,以便不可见时暂停粒子系统并在重新可见时恢复。
这样做的缺点是,屏幕之外的粒子会是静止的,这可能对某些效果有影响。避免这个缺点的方法是将粒子系统模拟快进一些来伪装粒子系统在不可见时仍然工作的假象。
参考:https://www.cgjoy.com/thread-186392-1-1.html
批处理
- 粒子单独使用一个layer,合批的效果会更好。
- 减少材质数量,用一个atlas纹理,便于合批,在shader中使用纹理坐标偏移。
- 深度排序,通过修改Order in Layer减少粒子渲染的穿插从而增大合批的概率。但通常由于相机的运动、粒子系统的分散分布等原因造成粒子系统之间的穿插,能够动态拼合的数量往往都是很少的。
取消脚本交互&物理碰撞
- 注意去掉Mesh Collider
思考:LOD & AIGC
传统做法:在性能分级的时候,就是直接关闭/开启某些特效。
更理想的情况应该是Lod,但是人为预制将带来可观的工作量。
是否可以利用AI实时预处理呢?
Profiler指标
ParticleSystem.particleCount
可以通过此统计同屏的粒子总数。如果是不想继续产生粒子,可以在逻辑中统计,然后根据需求使用pause等方式来控制粒子继续产生。
ParticleSystem.ScheduleGeometryJobs
是指在Culling之前主线程要等待子线程计算Particle的位置,然后才能Culling。往往在战斗界面开销较高。
-
- 考虑在中低端设备上尽可能降低粒子系统的复杂程度。
- 采用剔除方式,降低不必要的粒子系统Schedule开销。
ParticleSystem.Draw
调用次数对应的是粒子系统的DrawCall数量。
-
- 考虑减少粒子系统的数量。
- 可以通过使用TextureSheetAnimation的方式,或者通过修改Order in Layer减少粒子渲染的穿插从而增大合批的概率。
更多方案
1 序列帧
考虑替换为序列帧实现,比如一些细小的蝴蝶或蜜蜂群的效果。
2 Job化 & DOTS
。。。
3 Visual Effect Graph
如果要创建包含大量粒子的视觉效果并且需要高度可自定义的行为,请使用 Visual Effect Graph 而不是内置粒子系统。
Visual Effect Graph 利用 GPU 模拟粒子行为,可模拟的粒子数量远远超过内置粒子系统。