使用Sparticle创建高性能的粒子效果
制作高性能的粒子效果
Sparticle现在已经被广泛的应用到了大家的项目中。其中游戏是这个工具最主要的应用领域。对于任何一款游戏来说,除了品质之外,大家往往还注重另外一个方面——性能,这里的性能包括渲染开销,初始化开销,内存占用量等方面。只有性能达到一定的标准,我们才可能把它发布到正式的产品中。尽管这套粒子系统的实现上是非常高效的,充分利用了GPU的运算优势,但是作为工具的使用者,仍然需要遵循一些原则,使用一些技巧,这样才能制作出高性能的效果来。这篇教程将围绕性能的问题来深入地讨论。
粒子数量vs渲染面积
在制作粒子动画的过程中,大家往往习惯于统计粒子的总共数量来衡量一个效果的性能,于是设计师们在设计粒子动画时会变得畏首畏尾——即想做出更炫的效果,又怕粒子数量多了影响性能。我们先来看两个粒子效果的性能对比:
左边这个效果有5000个粒子,依然可以顺畅的运行。而右边这个效果只有100个粒子,但是却相当不流畅。(如果你的电脑运行两个都十分流畅,那说明你的电脑GPU比较强,请使用fork功能,然后自己把两边的粒子数量再设置大一点)。
这时候或许你这时候已经猜出其中的道理了,是渲染面积起了决定性的作用:前面一个效果虽然粒子数量很多,但是每个粒子都非常小,而后面一个效果粒子数量不多,但是每个粒子都占了相当大的面积。
在GPU的渲染管线中,粒子首先以顶点数据的形式进入运算单元中做运算,计算出每个顶点的时间,颜色,位置等等信息。然后GPU再将这些顶点组成一个一个的三角形,三角形中每个点就是屏幕上的像素点,并将刚才计算出的那些属性做线形插值,作为这些像素点的输入数据。然后GPU根据这些数据单独计算每个像素点的颜色。最后GPU再将重合的像素点以一定的规则合并成最终我们的颜色。试想一下,如果有5000个粒子,每个粒子由4个顶点组成,那么GPU需要计算5000*4=20000个顶点的数据。而如果一个粒子最终占屏幕面积四分之一,假设你的屏幕分别率是1920*1080,那么GPU需要对这个粒子计算1920*1080/4=518400个像素的值。尽管你可以说对于每个顶点的计算会比像素的计算复杂得多,但是这像素的数量和顶点的数量并不在一个量级之上。所以对于GPU来说,单个粒子最终映射到屏幕上的面积对性能的影响远远大于粒子的总数量。
对于传统的粒子系统,渲染粒子效果的时候, CPU还需要对所有的粒子遍历一次,进行一些必要的计算。如果粒子数量太多,那么CPU将会受到很大的计算压力。于是大家习惯于减少粒子的数量来提升性能。而在这套纯GPU计算的系统中,对于绝大多数的效果,CPU是不需要对粒子做任何计算的(这里有一个例外,在后面会提到)。如果你用scout这个工具来分析sparticle做出的效果的性能,你会发现CPU的消耗几乎为零。所以即使粒子数量再多,也不会影响到渲染时CPU的开销。
所以基于上面的分析,在用sparticle的时候,你更应该注意粒子占用面积而不是粒子的数量。当粒子占用的面积非常小的时候,请放心大胆地增加粒子数量来提升效果的品质。
渲染不透明物体
在制作特效的时候,我们需要根据粒子的特性来选择混合模式.
如果你选择的是normal混合模式,那么你还需要注意另外一个属性。先看这个对比的例子。
效果几乎一样,但性能差距却十分明显(如果你的电脑运行两个都十分流畅,那说明你的电脑GPU比较强,请把使用fork功能,然后自己把两边的粒子数量再设置大一点)。
在设置上,这两个效果的唯一区别就是左边的一个关闭了alphaBlending,而另外一个开启了alphaBlending。那么没有启用alphaBlending的一个会以不透明物体的模式来渲染。这就意味着对于多个粒子的重叠部分,如果GPU先渲染了前面的部分,然后再渲染被遮挡的部分,那么渲染被遮挡的部分的时候的像素计算就会被跳过。因为不透明的物体会完全挡住它后面的物体,既然已经计算出前面的不透明物体了,那么在它后面的区域就不需要再计算了。当然这个渲染顺序比较随机(我们无法保证GPU优先渲染前面的不透明物体),但是按概率来说是有很大概率发生的。这可以帮助我们极大的减少渲染面积从而提高性能。
以不透明物体的模式来渲染还有另外一个好处:确保先后粒子的远近次序是正确的。你是不是觉得左边那个看起来比较正常,而右边那个看起有点奇怪?再仔细看看你就就发现,右边那个效果中石头的前后次序混乱了,有些应该在后面的石头跑来了前面。由于这个教程的篇幅问题,原因我们就不解释了,有兴趣的读者可以看看这篇文章。
所以对于一些效果,如果粒子本身是不透明的,如树叶,碎石等,我们就要把alphaBlending关掉。在另一篇教程中,我们曾提到过做粒子效果一般都是用公告板配合贴图的形式来实现。像上面那个用石头的模型做粒子,制作起来是比较麻烦的。那现在我们来用公告板配合贴图的形式来做落叶的效果。落叶的贴图是这样的:
像刚才说的那样,我们把混合模式设置成normal,并且把alphaBlending去掉,那出来的效果就变成了这样:
其中应该透明的地方变成了不透明的黑色。为了解决这个问题,我们需要用到另外一个参数——alphaThreshold。把它设置成0.5,那么如果这个像素的颜色的alpha值大于0.5,那么就GPU继续处理,如果小于0.5,GPU就会放弃对于这个像素的后续处理,这就达到了我们让他透明的目的。最后大家可以看看这个完整的落叶效果:
动画数量的影响
为了做出复杂的效果,我们往往会将多个粒子动画组合在一起形成一个完整的效果。前面的两个章节我们都是在说渲染面积对于性能的影响。那么大量增加动画的数量对性能又有什么样的影响呢?我们来看这样一个极端的例子:
这个效果和本教成最开始的效果一样,但是由100个相同的动画组成,每个动画包含100个粒子。同样是5000个粒子,后面这种方式性能却差了很多。事实上,对于每一个动画,GPU都要单独来进行一次绘制,每一次绘制,GPU就需要改变一次状态,这样就无法保证一个持续的高速工作状态。就像我们开车,走走停停,自然不快。另外后面这种方式的初始化也需要更多时间,因为要初始化100个实例。
所以我们需要尽可能的减少动画的数量来提升性能,但这又和制作高品质的效果相矛盾。幸运的是,在某些情况下,我们可以利用一些技巧,把多个动画效果合并成一个动画。
1. 如果你有若干运动规律是一样的动画,但是这些动画产生的粒子的初始大小和角度是不一样的,那么你可以使用 model transform这个功能。为了方便和简明,我复用之前用过的石头模型来做了一个简单的例子:
可以看到这里每个石头模型的大小和方向都不一样。那么诀窍就是这个 model transform:
这里的设置比较容易理解,大家如果不明白可以fork这个效果来看看。
2. 如果你有若干运动规律是一样的动画,但是这些动画的贴图是不一样的。那么你可以把这些题图合成一张,然后用uv transform这个功能。看这个例子:
这个例子的贴图是一张包含了四种粒子图片:。你可以用你熟悉的画图工具来制作这张图。但是做的时候需要注意,首先你要把你的整张图平均分成若干个格子,比如说2行2列,那么就有4个格子,于是这个图就可以容纳4张不同的贴图。然后再按格子把你的原始粒子图片复制进去合成这张大图。sparticle中的设置如下:
其中,rows和columns告诉sparticle这张大图被分成了几行几列,这里是2行2列;index告诉sparticle每个粒子应该获取图片中的第几个格子,这里是在第1到第4个格子之间随即选取。
3. 如果你的动画非常复杂,难以用运动规律来构造,你可以用Sprite Sheet Animation这个功能来实现,看这个例子:
这个例子中,我们希望每一个粒子是一个蝴蝶飞翔的动画。这里我们用了这样一张序列图:
然后在sparticle中添加Sprite Sheet Animation节点,并设置如下:
和uv transform类似,rows和columns告诉sparticle有这张图有多少行多少列,这里是4行4列。Duration控制播放的速度,这里1表示播放一个周期需要花1秒钟。
拖尾效果
当我们效果被移动的时候,已经发射出来的粒子有两种选择,一种是跟着效果主体一起移动;一种是不跟着效果主体移动。后一种就就是所谓的拖尾效果。在默认情况下是不会形成拖尾效果的。你可以尝试打开上一章节中的那个例子(http://www.effecthub.com/item/398),然后点左下角move按钮看看移动的效果。
这就是没有拖尾的例子。再看另一个例子:
这就是托尾的效果。两者对比一下就知道,这个托尾的效果加了一个follow节点。
这里需要提醒一下,为了使这个follow正常工作,你需要把Time节点中的delay开启,设置一个大于每帧的时间间隔的数值,比如说你期望是60帧,那么每帧的时间间隔就是1/60,你必须设置一个大于1/60的值,这里我设置了0.1(远大于1/60)。
这个托尾的功能使得我们的效果增色不少,但是实际上follow是所有节点中最消耗性能的。之前我们提到对于绝大多数的效果,在渲染时CPU是不需要参与计算的,而唯一的例外就是这个follow。一旦加上这个节点,那么每次渲染CPU就需要遍历此动画中所有的粒子,计算它们的状态。如果粒子数量很少,比如数百个,那这个开销是完全可以接受的。如果太多,比如说一个场景中充满了这样的效果,那可能CPU就不堪重负了。
Follow节点还会导致另外一个问题——内存无法共享。对于其他的粒子动画,我们是可以几乎以零代价来复制一个新的,比如说一个场景中需要出现了多个一样的效果,那么我们可以只创建这样的一个效果,其他的完全由这个效果复制出来。那么这些效果实际上是共享一份内存的。但是对于Follow节点那部分内存来说,是无法共享的。
所以这个Follow节点会比其他节点更加消耗性能,如果不是必需的话,不要使用这个节点。需要注意的是一个效果可以有多个动画组成,不要认为想要拖尾的话,每个动画都要加这个节点,他们实际上是独立的,请参考sparticle模板示例中的2.awp。这个例子中,只有Animation1需要加Follow节点。
节点赋值的选择
经常有用户反映,他们在创作的时候会遇到这样一个错误:
Register overflow!
这实际上是由于对节点赋值的时候选择了太多变量导致的。那怎么区分是变量还是常量呢?很简单,如果一个属性的数值对于所有的粒子来说都是一样的,那么这个就是一个常量,反之,如果这个数值对于每个粒子可以是不一样的,那么这就是变量了。比如说对于一维的属性starTime,你选择的是OneDConst,并设置为1,
那么所有的粒子都会在1秒的时候出现,这就是常量。如果你选择的是OneDRandom,然后这样设置
那么粒子的出生时间就在0-10之间随机选择,即每个粒子是不一样的,那么这就是变量。对于三维属性来说,如果你选择的是ThreeDConst或者选择的是ThreeDComposite,并且子属性都是选择OneDConst,那这就是常量。
对于常量的属性,底层系统会利用常量寄存器来储存,对于变量的属性,底层系统就会利用流寄存器来储存。在GPU中,流寄存器的数量远远小于常量寄存器(比如在Flash的Stage3D中,流寄存器是8个,而常量寄存器是128个),所以如果你给你的节点设置了过多的变量,那么流寄存器就不够用了,就会出现刚才提到的错误。
使用变量还有另外一个缺点:需要更多的初始化时间和更多的内存。因为常量数据是在所有粒子间共享的,只需要一份,而变量是每个粒子都需要单独一份。
所以大家在对节点赋值的时候应该要尽可能的选择常量,当然也不可能所有属性都选常量,不然所有的粒子就会呈现出同样的状态。
另外大家还需知道的是只有Behaviors中
的节点会涉及这个问题,而其他地方,比如geometry中的
model transform和uv transform中设置的属性并不会占用寄存器。
结尾
制作高性能的粒子特效是非常值得大家共同探讨的话题,如果你有什么问题或者是想法,欢迎在下面讨论。
You must Sign up as a member of Effecthub to view the content.
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
14160 views 18 comments
You must Sign up as a member of Effecthub to join the conversation.
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
请问下大神,不想要粒子z轴以下部分显示出来有什么好办法吗?
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
好人
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
这篇教程写得非常清楚明了,针对我们新手要是能多些教程就好了
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
好棒的教程!学习了。
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
大神 我想问这个软件就是做特效的对吗 能导入带蒙皮动画的模型吗?
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
请问有没有老版本的Particle可以用。因为目前我们的项目使用的是Away3D 4.1.0而现在网上下载的加载代码是使用的4.1.4 如何才可以方便的将awp加载到我们4.1.0的项目中?
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
廖老师你好:我是新人,想学习啊这个软件,可以发些基础教程给我吗?谢谢!
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
廖老师,最新的SParticle添加了heat功能,这个效果如何在Away3D中实现呢?能不能具体说一下实现思路,谢谢。
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
@error_110 这对遍历场景,计算矩阵还有骨骼动画等会有所提升,但是对于GPU的渲染不会有帮助。 我想Away3D这样的渲染引擎CPU计算密度不是太大,如果是计算密度更大的物理引擎,才更有必要用Flascc来重写。
@Liao Cheng 谢谢您 廖老师。现在是同屏多人或是战斗激烈时会卡顿,动作融合,场景遍历,拖尾特效,子弹命中测试都很占cpu的。
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
廖老师: 如果我把away3d使用flascc, as3wig编译成swc, 再使用会对性能有多大的提升呢? 或是把awawy3d用c/c++重写,对性能的提升有多大呢?
@error_110 这对遍历场景,计算矩阵还有骨骼动画等会有所提升,但是对于GPU的渲染不会有帮助。 我想Away3D这样的渲染引擎CPU计算密度不是太大,如果是计算密度更大的物理引擎,才更有必要用Flascc来重写。
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
廖老师: 如果我把away3d使用flascc, as3wig编译成swc, 再使用会对性能有多大的提升呢? 或是把awawy3d用c/c++重写,对性能的提升有多大呢?
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
很有帮助的教程
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
文笔不错。入门好文章,优化建议很具体。感谢!
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
very useful for chinese users !
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
lua脚本编辑器 可以用么?
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
cool!
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
廖大师好文章 !顶起!!