作为游戏引擎渲染逻辑模块内的一个常见功能,粒子频繁的创建/销毁需要做好内存管理,内存池,AoS(Array of Struct) or SoA(Struct of Array)。同时更新的粒子数量如果很大,需要考虑SIMD指令优化,使用多线程,或者是实现GPU粒子。本文会记录新开发的游戏引擎内粒子系统的设计思路。

中间件

  • Effekseer : MIT开源
    • https://effekseer.github.io/en/
    • 与我们的游戏引擎对接
      • 图形API
        • 复杂度在于跨平台游戏引擎并不是固定的DirectX或者OpenGL,我们需要对接引擎RHI的每一个渲染后端
      • 资源转换
        • Textures
        • Shaders
          • effekseer的shader跨平台方案是人工编写DirectX11,通过glslang搭建的工具去生成其他语言
          • bgfx的方案则是基于glsl语法改造的新语言,所以我们需要转译effekseer的shader代码到bgfx里
      • 上述工作的开发已经由云风的团队开了个头,我们可以考虑使用他们的方案一起维护:https://github.com/cloudwu/efkbgfx
  • PopcornFX

选用中间件的好处是我们无需去开发粒子编辑器以及相应的工具链,也无需游戏项目组招美术特效人员进行特殊培训,只需要完全游戏引擎的对接工作。另外,中间件如果使用较广的话,游戏项目可以导入它们现成的大量资源到游戏引擎中使用,测试。

运行时

  • 内存布局
    • SoA vs AoS
      • SoA可以节省掉多余的内存,如果某个粒子不需要某个属性,而AoS则必须全部持有
      • SoA索引数据比较麻烦,需要能从某个粒子ID在不同类型的数据数组中索引到对应的数组,以及数据数组也可能因为粒子更新产生空洞,而AoS则方便查询
  • 运算
    • Stateful vs Stateless
      • 举个例子,Stateful指的是粒子会存储当前位置在内存中,Stateless则是粒子每次都根据度过的时间计算当前位置
      • 某些公式可能无法使用Stateless的方式,但Stateless能节省内存
  • CPU粒子
    • 优先实现,对于游戏项目来说同屏粒子数量的规模大多数时候用不上GPU粒子的方案
    • 多线程
    • SIMD优化
  • GPU粒子
    • 补充实现,用于加速同屏大量粒子的情况

功能对比,参考

可以去跟一些开源引擎的实现方案进行对比

  • Unreal Engine
    • Niagara Particle Systems

参考链接