0%

粒子系统设计随想

首先是关于粒子系统的概念,维基百科上是这么描述的:

粒子系统表示三维计算机图形学中模拟一些特定的模糊现象的技术,而这些现象用其它传统的渲染技术难以实现的真实感的游戏图形。经常使用粒子系统模拟的现象有火、爆炸、烟、水流、火花、落叶、云、雾、雪、尘、流星尾迹或者象发光轨迹这样的抽象视觉效果等等。

除过影视行业,CG 特效在游戏领域中也有着广泛的应用,往往用于强化视觉、动作张力的表现,或是丰富一些细节处理,使得游戏体验更加细腻。因此,在游戏引擎中,粒子系统往往承担着实现特效效果的重要角色。

早期的粒子系统,设计时通常会提供好各种固定功能的模块,诸如控制粒子的大小、颜色、方向等属性,对于特效设计人员来讲,只要在一个可视化的环境下,调节好各种参数即可。通常根据指责可划分成三个阶段:发射影响渲染。所以不管哪个游戏引擎的粒子系统,难免会经常看到诸如EmitterRenderer等之类的词语。

如下图所示,一个粒子根据上述三个阶段依次由出生(确定位置、速度、颜色、大小、初始旋转),到接受更新影响(变化参数可以是随机值、曲线等),最后根据渲染设置来重新组织、生成粒子的顶点数据并进行绘制。不同人设计出来的粒子系统可能看起来千差万别,但回归本质不难发现,谁也逃不出这三个步骤。

基础Particle Pipeline

这种模式有点类似早些年图形渲染中的“固定管线”,虽说一定程度上限制了设计人员的发挥,但是针对不同的特效,往往会衍生出固定的“套路”来。更新粒子模型、贴图,再配合上胶水代码(例如Lua脚本)来控制一些动态输入参数以及事件处理,基本上可以满足大部分的效果需求。

ParticleSystem Modules

上图展示了一个功能基本完备的粒子系统模块流水线,主要借鉴了Unity中粒子系统的相关Module,笔者也曾在一款基于移动端的自研游戏引擎中,搞过一套功能几乎一样的粒子系统。下图则是Unity中一个ParticleSystem组件的基本Module分布:

Unity ParticleSystem Component

细致的模块划分,除过行业经验的积累,更主要还是为了功能解耦。我们知道,一个特效效果,往往是调试出来的,谁也没法准确的设定某个特效的具体参数,也仅仅是凭借脑子里的经验模型来不断试错。如果粒子系统的功能模块过于耦合,在游戏引擎迭代的过程中很难保证向下兼容,之前做的效果又要推倒重来,并且也不利于特效美术建立“经验模型”。

其实早在Unity 5.x时代的粒子系统,每个模块的很多参数支持以及像Lights、Custom Data这类更高级一些的特性都还没有支持,这都是在引擎版本迭代中慢慢积累起来的。每一次更新,无疑都会解放一部分特效制作人员的思维束缚,以及提高不少的产出效率。

在与不同项目的特效美术同事打交道的过程中,我发现他们大多数都把粒子系统当做一个黑盒来使用(诚然确实也没办法去深刻理解引擎内部的具体实现),即便产生了一些特殊的制作思路,但碍于引擎更新迭代的各种成本,也都退而求其次以另一种方案来进行替代。但相比较于Unity这类商业游戏引擎,自研引擎也有一定的独特优势,就是可以根据项目需求来快速扩展制定出特殊的功能模块,也许并不是通用的最优解决方案,但无疑能提升生产力以匹配项目进度。

这类“固定管线”形式的粒子系统伴随着整个游戏行业繁衍了很长时间,直至UnrealEngine发布了它们的全新粒子系统:Niagara

它采用类似Houdini那样的可视化节点的形式来制作特效,而不是传统的表格形式的参数调配。组织形式上与Unity的ParticleSystem也有一定的区别。

Niagara编辑主界面

如上图,这是NiagaraSystem的主界面,它的混合结构与Unity的ParticleSystem有着不小的差别。这里的NiagaraSystem是一个复合特效效果的集合,它里面由若干个Emitter组成。Niagara的Emitter并不仅仅对标之前所提的发射阶段,也包含了影响阶段和渲染阶段的全部功能。因此,一个Emitter更像是对标Unity中的ParticleSystem组件。在Unity中制作一个特效,往往需要一个树形结构下的多个GameObject分别挂载着不同的ParticleSystem组件组合而成,其中每个ParticleSystem负责发射一类粒子。

其实两者的实现目的都是一致的,但是Niagara的形式更符合美术的思维习惯,也更容易专注于效果的调试与制作,不用再牵扯精力去关心Transform组件或是整体的Node层级结构,全部放到一起,更加地一目了然。

推荐阅读虚幻的官方文档《Niagara关键概念》来理解Niagara的相关理念。其中,它的VFX系统目标,个人还是十分赞同的:

  • 美术师可全权掌控效果
  • 各轴均可编程、可自定义
  • 提供更好的调试、显示和性能工具
  • 支持来自虚幻引擎4其他部分或外部源的数据
  • 不妨碍用户操作

关于Niagara的强大,完全可以再开一篇甚至是多篇文章来详细介绍。这里想要强调的是,它完全实现了功能模块的可定制化。鼠标双击Emitter中的任意Item,会跳转到一个新的Niagara Script窗口,如下图所示:

Niagara Script Graph

类似蓝图的Graph实现了对应Module下的全部功能逻辑,可以称之为Niagara脚本,具体源码实现在UNiagaraScript类中,继承自UObject,并且对应着一种资产。因此美术可以创建自己的Niagara Module ScriptNiagara Function Script,灵活地应用于Emitter之中。也就是说,美术终于能够自己独立实现Module的逻辑了,不再受限于程序开发。

对于创造力十足、很有想法的特效美术来说,这无疑是一巨大福音。

但凡事都有两面性,很多时候我们可能并不需要放飞自我、无节制的创造,80%的制作还是离不开那几个老生常谈的参数。为此,Niagara也提供好了很多内置模块,方便大家像之前那样快速、直接地搭建出基础的粒子效果出来。即便这样,Niagara的学习成本无疑还是大大增加了。而且对于程序开发人员来讲,很多Module的逻辑通过Graph的形式阅读起来也比较头疼,虽然可以插入Custom HLSL代码(Niagara Script本质就是使用HLSL编译模块),但用起来也会有许多坑在里面。

说到这里,Niagara的思路对现代游戏引擎的粒子系统设计还是有着非常多的借鉴意义。它解决了美术制作特效的最大痛点,并能更好地去进行效果调试和性能调优。

归根结底,特效的制作工作流无论怎么完善,粒子系统无论怎么设计,其根本出发点无非就是:产出效率运行效率。无论是制作一款3A大作,还是移动平台的休闲游戏,虽然需求形式大相径庭,但也逃不过上述两点。基于这两个出发点,以及以往的经验和一些商业引擎的借鉴,整理了如下一份粒子系统设计的思维导图:

Particle System Design

想要为游戏引擎设计出一款好的粒子系统,除了老生常谈的基于SOA架构的DOP模式,支持应对海量粒子模拟的GPU方案,还要包括强大、便利的数据通信能力,包括并不仅限于粒子系统内部,游戏引擎的其他模块,甚至于针对外部资产数据的处理和交互。

编辑器的配套支持也是尤为重要的,毕竟粒子系统的内核设计的再完美,架构再优越,最终也是要给人来用的。抛开一些硬核功能的支持不谈,如果操作过于繁琐甚至于workflow上有些反人类,都会导致它不能被大众所接受。往往使用粒子系统更多的还是美术从业人员,因此从他们的角度、思维习惯来设计十分重要。此外,粒子系统也常常是需要进行性能优化的地方,为了平衡美术与程序在效果与性能之间的根本冲突,完备的性能调试辅助工具也是需要的,以数据事实说话节约沟通成本,也有助于系统设计初期暴露出一些隐藏的性能问题。

最后,这篇文章可能有很多不够严谨或是值得商榷的地方,欢迎各路特效大神来指点、交流。 )

想要为游戏引擎设计出一款好的粒子系统,除了老生常谈的基于SOA架构的DOP模式,支持应对海量粒子模拟的GPU方案,还要包括强大、便利的数据通信能力,包括并不仅限于粒子系统内部,游戏引擎的其他模块,甚至于针对外部资产数据的处理和交互。

编辑器的配套支持也是尤为重要的,毕竟粒子系统的内核设计的再完美,架构再优越,最终也是要给人来用的。抛开一些硬核功能的支持不谈,如果操作过于繁琐甚至于workflow上有些反人类,都会导致它不能被大众所接受。往往使用粒子系统更多的还是美术从业人员,因此从他们的角度、思维习惯来设计十分重要。此外,粒子系统也常常是需要进行性能优化的地方,为了平衡美术与程序在效果与性能之间的根本冲突,完备的性能调试辅助工具也是需要的,以数据事实说话节约沟通成本,也有助于系统设计初期暴露出一些隐藏的性能问题。

最后,这篇文章可能有很多不够严谨或是值得商榷的地方,欢迎各路特效大神来指点、交流。

您的赞赏是我前进的动力

欢迎关注我的其它发布渠道