超长干货!Cocos Creator 粒子系统详解,零代码实现逼真自然效果
在上一篇《Cocos Creator 渲染实战:地编篇》中我们主要介绍了 3D 户外场景的搭建,本文中我们将了解粒子系统的使用方法和一些典型自然效果的实现,制作一个粒子效果的通常流程是:
使用贴图或模型决定每个单独粒子的形态,创建相应的粒子材质; 创建粒子系统,决定粒子的发射频率、密度和飞行速度; 使用动力学模块添加动态变化,模拟物理效果; 将粒子系统移动到场景中合理的位置。
PS. 本文将分为基础-烟雾(普通粒子)-性能优化-星光(动画粒子)-降雨(3D 粒子)-火焰(复合粒子)-喷火和烛火(粒子的变体)几个部分,篇幅较长,建议先马后看。
基础
RateOverTime
参数从 10 改为 1。在场景编辑器中,按下左下角播放控制的重置按钮,使粒子系统从头开始重新渲染。StartSpeed
参数从 5 改为 2.5。StartLifetime
参数,从 5 改为 10。StartSpeed
从 2.5 改回默认的 5,又会怎样呢?RateOverTime
和 StartLifetime
都没有变化,所以我们仍然保持了粒子总数为 10 个的状态,但由于 StartSpeed
增加了一倍,因此在相同的时间里,粒子能够飞行的距离增长了一倍。换句话说:粒子之间连线的长度增加了一倍。RateOverTime
、StartSpeed
和 StartLifetime
这三个参数之间,观察到一定的规律:RateOverTime
控制每秒发射粒子的个数;StartSpeed
控制粒子被发射出后飞行的速度;StartLifetime
控制粒子的生命周期,即粒子被发射出后能够存在的时长。当生命周期结束之后,粒子会自动从场景中消失。
当前同时存在的粒子个数,大概等于每秒发射粒子的个数与粒子生命周期的乘积,即 RateOverTime
*StartLifetime
;粒子能够飞行的最大距离,大概等于粒子飞行的速度与粒子生命周期的乘积,即 StartSpeed
*StartLifetime
;降低相邻两个粒子之间的距离,或增加粒子的密度,可以在粒子能够飞行的最大距离( StartSpeed
*StartLifetime
)不变的情况下,增加每秒发射粒子的个数(RateOverTime
),反之同理。
Effect
参数选择为 builtin-particle
。MainTexture
,然后依据需要使用 TintColor
参数对颜色和 Alpha 进行微调即可。保存对材质的修改,回到粒子的属性检查器中,将粒子材质拖拽到 Renderer 标签下的 ParticleMaterial
参数上。RenderMode
参数进行选择。我们在前文中提到过使用 Billboard 配合一张渐变贴图制作体积光的假象,同样的方法我们可以使用在粒子系统上:粒子系统经常用作模拟的烟雾、火焰、光斑效果,实际上都是使用一张平面的贴图,来模拟现实中有一定体积的效果。因此,Billboard 也是粒子最常见的渲染方式。烟雾(普通粒子)
烟雾最终效果
TintColor
参数为贴图赋予一定颜色,因为 Billboard 渲染的缘故,面片始终保持正对摄像机,乍一看确实有些许带有体积的团状物的意思。Technique
参数控制,在默认的 Add 模式下,使用的粒子贴图不需要考虑其透明程度,只需要确保我们希望是透明的部分在贴图中是纯黑色就行。即便是肉眼看不出区别的明度极低的深灰色,也会在 Add 模式下留下贴图边缘的痕迹,导致“抠图抠不干净”的问题出现。同理,我们不用在不透明的部分包含任何颜色信息,因为我们可以直接通过材质的 TintColor
参数调节颜色,如果贴图本身已经包含了颜色信息,粒子材质就会产出两种颜色的混合,让精确控制粒子颜色变得很困难。TintColor
参数调为黑色,你会发现粒子完全消失了,这是因为贴图所有的像素都被设为了黑色,因此被 Add 模式视为完全透明了。Technique
参数选为 1-alpha-blend
。这种模式与 Add 模式相反:只有半透明的像素会被叠加到 Frame Buffer 上,而不透明的像素则会保留自身的颜色。所以在使用这种混合模式时,我们需要一张有明确 Alpha 通道的贴图,同时,因为不透明的像素颜色得到了保留,我们可以在 TintColor
参数中使用黑色,这不会导致粒子的消失。StartSize
参数中输入一个更大的数值来实现。StartRotation
参数可以为粒子赋予旋转角度,输入一个数值,得到的结果是每个粒子都相应地改变了角度,每个粒子仍然是一摸一样的。有没有可能在每个粒子生成时,给它们分别获得一个随机的旋转角度呢?StartRotation
参数末尾的倒三角,可以得到一个数值类型的菜单。目前已选择的是 Constant
,表示 StartRotation
参数只接受一个常量数值。在菜单中选择 TwoConstants
,StartRotation
参数发生了变化,我们需要输入 ConstantMin
和 ConstantMax
两个数值,即一个最大值和最小值。StartSize
)、飞行速度(StartSpeed
)和生命周期(StartLifetime
)加入随机性。ShapeModule
将开启发射器相关的参数设置。RandomDirectionAmount
和 RandomPositionAmount
参数,能够让粒子发射的方向和位置在发射器的基础上增加一定的随机性。而 SphericalDirectionAmount
参数能够让粒子在无视发射器的情况下,增加向四周所有方向发射的随机概率。RotationOvertimeModule
开启该模块。这个模块的功能是让每个粒子在飞行的过程中每秒依据一定的角度旋转。当然,也可以为它的参数赋予一个随机值的区间,让每个粒子旋转都有细微的差别。SizeOvertimeModule
开启该模块。与 RotationOvertimeModule
不同的是,这个模块的参数只是让每个粒子依照 StartSize
已经设定的大小按照一定数值倍数缩放,即便给予它最大值和最小值,也是让每个粒子在区间中随机取值缩放。烟柱整体等大的问题并没有解决。这时就需要我们调用另外两种数值类型:Curve
和 TwoCurves
。Curve
,点击参数的输入框,弹出曲线编辑窗口。SizeOvertimeModule
的数值,那么横轴当然代表大小缩放的倍数。默认情况下,曲线是一条水平直线,这与我们输入一个常数数值的效果相同:粒子从出生到生命周期结束,都使用同样的缩放倍数。我们的目标是一个上大下小的烟柱,换句话说,粒子应当在出生时较小,随着生命周期逐渐放大,在生命周期结束时达到最大。用曲线翻译这种逻辑:我们要的是一条从左往右“一路上坡”的曲线。Preset
标签下快速选取一个符合我们要求的曲线,最简单的当然是从 (0, 0) 到 (1, 1) 的直线,而它所产生的效果当然也是粒子从新到旧大小线性递增,形成近乎锥形的烟柱。RotationOvertimeModule
的功能模块,如果在 RotationOvertimeModule
输入曲线数值,会出现什么效果呢?RotationOvertimeModule
的功能是让每个粒子在飞行的过程中每秒依据一定的角度旋转。所以它的参数数值实际相当于旋转的速度而非位移值,因此如果给予它曲线数值的话,会出现粒子随着生命周期旋转越来越快或越来越慢的效果。ForceOvertimeModule
为飞行中的粒子增加一个力的影响。虽然烟雾使用的是 2D 的贴图,但是粒子都是在 3D 的空间中发射的,所以也可以从 x, y 和 z 三个轴向分别向粒子施加力的影响。同样的,我们可以使用曲线数值代替常量数值,为其增加动态的变化。TintColor
参数实现了不同颜色的烟雾。然而现在需要调整的是烟柱整体的颜色变化,修改 TintColor
只会对所有粒子的颜色无差别地更改,所以在粒子材质中,仍然使用纯白色。ColorOverLifetimeModule
开启该模块。这个模块与我们之前接触的模块很相似,它的参数默认接收一个常量颜色,使用常量颜色与更改粒子材质颜色的效果相同,将产出一个全部粒子无差别染色的烟柱。ColorOverLifetimeModule
也可以接收两个常量颜色(TwoColors
),这与我们之前接触的 TwoConstants
也没有本质区别,每个粒子将会在两个常量颜色之间随机选择颜色,形成一条颜色斑驳的烟柱。我们今天要使用的,是第三种数值类型 Gradient
。SizeOvertimeModule
的控制粒子非常小,因此影响不大,但在粒子消失的时候这种生硬的消失非常影响观感。ColorOverLifetimeModule
非常适合解决这个问题,我们只需要创建一个头部和尾部 Alpha 值都为 0 的颜色渐变,就可以让刚发射出来和即将消失的粒子变为全透明,只保留中间的主体部分。在此基础上,我们依据从参考图中观察到的颜色变化,在渐变上创建几个不同明度的灰色节点,就可以制作出由暗渐渐转淡的颜色变化效果。烟雾飞行的太快或太慢?调节 StartSpeed
;烟柱太高或太低?确定 StartSpeed
的基础上,调节StartLifetime
;烟雾太稀薄或太厚重?确定 StartSpeed
和StartLifetime
的基础上,调节RateOverTime
,也可以调节粒子材质TintColor
的 Alpha 值;让烟雾从细小的出气口喷出,或从一篇区域内喷出,或无差别朝四面八方喷出?调节 ShapeModule
;烟柱太细或太散?调节 SizeOvertimeModule
;烟雾看上去太死板或太乱?调节 RotationOvertimeModule
;烟雾飘散的方向不对?调节 ForceOvertimeModule
;烟雾的颜色不够丰富?调节 ColorOverLifetimeModule
。
性能优化
Capacity
参数。它的作用逻辑是:当粒子系统中同时存在的粒子数量高于 Capacity
所指定的数值时,粒子系统会暂时停止发射粒子,等待现有的粒子生命周期结束,直到当前的粒子数量降到低于 Capacity
数值时,粒子的发射才会依照正常情况恢复。所以当我们调高 RateOverTime
参数到一定程度时,会出现粒子发射“断断续续”的情况,这正是 Capacity
参数在发挥作用。RateOverTime
)之外,还需要将允许同时存在的粒子个数(Capacity
)控制在最小的范围内。所幸的是,同时存在的粒子个数可以通过 RateOverTime
* StartLifetime
推算出来。因此我们只需为 Capacity
取一个略大于 RateOverTime
* StartLifetime
的数值,确保 Capacity
不会导致粒子暂停发射,就能在不影响效果的前提下保证粒子系统的执行效率。RenderCulling
,按下 Generate bounding box
,引擎会根据粒子可能会飞行到的区域形成一个边界盒。在开启 RenderCulling 的情况下,如果边界盒没有出现在摄像机可观察到的范围中,则整个粒子系统不会被渲染;当边界盒重新回到摄像机的视野内,粒子渲染会重新开启。边界盒的大小可以手动通过参数进行调节,开启 RenderCulling 可以避免在粒子没有被观察到的情况下,消耗无意义的渲染资源。星光(动画粒子)
Free Texture Packer 下载:
http://free-tex-packer.com/download/
Add Images
,全选图像序列中的所有图片导入。Scale
滑块,可以看到堆叠后的精灵图集的预览。在右侧的属性栏,可输入生成精灵图集的相关参数。为了正确适用在粒子系统上,需要做出如下的参数设置:将 Packer
设为MaxRectsBin
将 Method
设为BottomLeftRule
不要勾选 Detect identical
不要勾选 Allow rotation
不要勾选 Allow trim
Padding
和Extrude
都为 0
Width
和 Height
参数中输入理想中的精灵图集分辨率大小,如果当前导入的图像序列中的图片太多,可能会出现一张精灵图集放不下的情况,软件会自动将放不下的部分放入第二张图集。这当然不是我们想要的结果。调整 Width
和 Height
的数值,尽量充分使用一张图集的空间,同时保证所有的图片都能够放入一张图集中,我们不需要保证 Width
和 Height
的数值一样或 POW 数值,因为在图集生成后,可以再用 Photoshop 打开整体缩放为我们理想的大小。Save path
输入存储目录,点击 Export
即可生成图集。ShapeModule
模块,选择一个球形的发射器。可见,在默认情况下,粒子会从球形的各个方向随机发出。StartSpeed
设为 0。StartSpeed
为 0 时,粒子生成后不会向外飞出,而是会停留在诞生的位置。为了保证粒子只会在发射器的外部生成,还可以在 ShapeModule
模块下的 EmitFrom
参数下选择 Shell
。ParticleMaterial
参数下。TextureAnimationModule
开启相关模块。精灵图集是图像序列的集合,所以需要告诉模块它是怎样集合的:观察精灵图集,记下它的行数和列数,分别输入 NumTilesX
和 NumTilesY
中。FrameOverTime
参数实现,我们在前文中中提到过参数的曲线数值:曲线的横轴为粒子的整个生命周期,曲线的竖轴为数值大小。因此,需要为 FrameOverTime
输入一个曲线数值,由曲线的取值实现动画的效果。最简单的方式当然是使用从 (0, 0) 到 (1, 1) 的直线,这意味着随着粒子生命周期的流逝,线性地使用精灵图集中的每一张图像序列,这种方式与我们常见的视频播放是一样的。CycleCount
参数中,如果数值为 0,则精灵图集不会播放,粒子会停留在序列的第一帧上;如果数值大于 1,则粒子在生命周期的过程中会循环播放相应的次数。StartLifetime
),或者增加生命周期中播放的次数(CycleCount
)即可。TextureAnimationModule
模块还可以用于制作各种其他的效果。比如:我们想用粒子制作一个花瓣飞落的效果,希望花瓣在飞落的过程中有更多腾挪翻转的变化,用 3D 的花瓣模型又有点死板,那么我们就可以先制作一个花瓣 2D 变形的动画,导出图像序列转换为精灵图集来作为每个花瓣的粒子。这样不仅用 2D 粒子代替了 3D 粒子从而获得了更大的性能空间,而且让美术能够自由地决定花瓣的各种姿态。降雨(3D 粒子)
无论是烟雾还是星光,它们都是通过利用 2D 资源来实现 3D 效果的假象。那么,是否能使用真正的 3D 模型作为粒子呢?我们下面将要制作的降雨的粒子效果,就需要 3D 模型作为粒子来实现。
最终的效果呈现需要两个独立的粒子系统:空中落下的雨点和在地面溅起的水花。目前 Cocos Creator 中尚不支持 Sub-particle 系统,也就是说,我们无法在一套粒子系统的粒子落下的位置启动另一套粒子系统的发射。然而,这并不会影响我们制作较为满意的降雨效果。
液体的呈现通常较为令人头疼,我们可以先从雨点和水花的材质说起。
现实中下落的雨点会因为光线折射而产生高亮的效果,所以雨点通常比背景中的景物看上去更亮一些,在背光的角度观察时尤其如此。雨点粒子的材质比较简单,我们只需要制作一张飞行中雨点的贴图,配合材质不同的 Alpha 混合模式实现明度上的差异化即可。虽然雨点在空中飞行时有自身的形态,但是我们不必特别关注,因为无论是怎样的降雨效果,雨点都只会在我们眼前一瞬而过,再加上有动态模糊的因素影响,飞行中的雨点完全可以抽象为一条细长的柱状物。我们只需要稍微给它一点厚度,保证折射的高亮可见即可。
既然如此,雨点的贴图就很容易绘制了:在 Photoshop 中使用画笔工具,绘制若干白色竖条即可。如果追求细节的话,可以在竖条上增加一些小的圆形突起,模拟雨珠聚拢成流的感觉。最后,还可以在绘制的竖条上增加一层径向模糊,模拟下落时的动态模糊效果。
然而,仅仅靠若干下落的竖条,可能太过于单调。加上雨点落在地面溅起的水花效果,可以使降雨的感觉更让人信服。
从参考中可以观察到:当雨点落在地面时,会溅起近似于圆柱形的水花,随后,水花从上至下开始塌陷,圆柱形的水花也逐渐变成上大下小的圆锥形,直到完全塌陷变成一个平面与地面融为一体。
既然需要水花的效果,我们可以收集一些水花的素材。与雨点同理,素材的颜色和精度并不重要,只需要大概的水花的造型。套用我们在制作烟雾时的处理流程,对素材进行去色、色阶处理,最后加上一层径向模糊。毕竟水花和雨点一样,只会在我们眼前短暂地闪过。
贴图制作完成之后,将它们导入引擎制作粒子材质。这次,我们将使用 GPU 粒子材质:打开 Effect
参数的下拉菜单,选择 builtin-particle-gpu
。
雨点的粒子系统非常简单:开启 ShapeModule
选择方盒形的发射器,将发射器旋转 90 度使其垂直向下发射。将整个粒子系统的父节点移动到垂直高度较高的位置,调节飞行速度(StartSpeed
)使粒子以接近雨点下落的速度飞行,调整生命周期(StartLifetime
)使粒子在大致落到地面时正好生命周期结束。
由于我们为雨点创建的粒子材质适用于 GPU 粒子,相应的,粒子系统需要勾选 UseGPU
参数。
GPU 粒子与我们之前使用的普通粒子相比执行效率更高,考虑到 3D 模型的使用,所以我们在制作降雨效果时选择使用 GPU 粒子。但是,降雨效果的所有实现方法,使用普通粒子都可以实现。
回雨点贴图,你会发现这其实是一张精灵图集,包含了四张雨点的贴图。然而,这四个贴图并不是一个序列,它们并不能组成一段动画,我们希望雨点粒子随机在这四个贴图中选择一个使用。那么,这种效果该如何实现呢?
开启 TextureAnimationModule
模块,在制作星光的过程中,我们用它实现了精灵图集动画的功能,也能使用它让粒子在精灵图集中随机选择一个序列作为静态贴图。我们仍然需要告诉 TextureAnimationModule
精灵图集是如何组合的,在 NumTilesX
和 NumTilesY
中分别输入精灵图集的行数和列数。由于不再需要动画效果,因此也不再需要给 FrameOverTime 曲线数值,让它保持默认的常数值 0 即可。StartFrame
控制动画起始帧,既然没有动画效果,粒子就会静止在 StartFrame
所定义的帧数。还记得我们使用最大值和最小值制作随机效果的技巧吗?同理可以为 StartFrame
设定最大帧值和最小帧值,让粒子系统在其中随机取帧(注意:最小的帧数是 1,不是 0)。最后,我们仍然需要为 CycleCount
输入数值,因为虽然没有动画,粒子系统仍然需要循环精灵图集中的所有序列以随机取帧。
雨点的随机取帧有了,但是雨点的贴图遭到了非常严重的拉伸。这是由于雨点贴图并不是一个正方形,粒子在 Billboard 的渲染模式下,会将贴图拉伸到 1:1 的长宽比。要解决这个问题,我们可以使用之前了解过的 StartSize
参数。
默认情况下,StartSize
模块对粒子大小的控制是等比的,我们可以勾选 StartSize3D
,在 StartSizeX
、StartSizeY
和 StartSizeZ
轴分别输入数值,将粒子缩放到符合雨点贴图的比例。
问题虽然解决了,Billboard 还有另外一个问题:Billboard 是永远正对摄像机的。但是我们不希望场景中落下的雨点永远正对摄像机:们低头观察时,雨点应当从我们的观察角度纵深掠过,而不会仍然是一条竖线。所以,Billboard 已经不适合用于雨点的粒子了,我们需要真正的 3D 模型作为雨点的粒子。
将 Renderer 标签下的 RenderMode
参数选择为 Mesh
,这将会使每个粒子以 3D 模型的形式发出。随后,在下方的 Mesh
参数中选择使用的模型。我们可以把任何导入模型的网格文件拖拽到 Mesh
参数中。这里一个简单的面片就能达到目的,所以可以使用引擎内置的四边面模型 quad.mesh
。
虽然使用了 3D 模型作为粒子,但是生成的每个粒子依然面朝一个方向,我们还需要让每个粒子在出生时获得一个随机的旋转数值。StartRotation
参数我们之前已经使用过了,与 StartSize
类似,勾选 StartRotation3D
,在 StartRotationX
、StartRotationY
和 StartRotationZ
中分别输入数值,或使用最大值和最小值定义随机的范围。
回到雨点的粒子材质:Add 模式对于雨点来说还是太强了,在 Technique 参数中,选择 2-add-multiply
,在这种模式中,粒子的像素会首先与 Frame Buffer 中的像素线性相乘(相当于 Photoshop 中的正片叠底),然后线性相加到 Frame Buffer 的像素上。这样可以使粒子提亮场景的同时混合了场景中的颜色,更接近雨滴折射环境中的光线而产生的高亮效果。
最后,依照我们想达到的降雨强烈程度调整一下粒子发射的频率(RateOverTime
),调整父节点的旋转参数为降雨引入一定的倾斜度,雨点部分就制作完成了。
下面我们需要制作地面上的水花。将雨点粒子的父节点复制一份,移动到接近地面的位置。飞溅的水花会留在地面上,不会向一般的粒子一样向外飞去。我们在制作星光的过程中已经处理过类似的问题,将 StartSpeed
设为 0。
回到 ShapeModule
模块,给方盒形的发射器的 Z 轴一个较小的 Scale
值。我们希望得到一个厚度极细的方盒形发射器,这样能够给发出的粒子细微的高度变化。
我们在制作雨点时已经使用了 3D 模型作为粒子,毫无疑问水花的粒子同样需要 3D 模型,更重要的是,这个 3D 模型能够实现在参考中观察到的从柱形、锥形到平面的变化。由于粒子系统只能接受网格文件作为 3D 模型,所以在 DCC 中制作动画显然是行不通的。只能通过之前使用过的旋转、大小等模块,来实现水花形变的效果。
那么,我们需要怎样的模型呢?
既然已经有了水花的贴图,那么我们可以从一个面片入手:新建一个简单的面片,给予它一定数量的网格密度。通过弯曲变形,将平面修改成四角突起、中间凹陷的形态。确保模型的锚点( Pivot )在凹陷的中心位置,这样可以保证模型会从凹陷的部分开始形变。
将模型导入导入引擎,并将网格文件拖拽到粒子系统 Renderer 标签下的 Mesh
参数上。
首先把水花贴图应用在模型上。水花贴图同样包含了 4 种不同的变化,我们可以使用在处理雨点时同样的方法,使用 TextureAnimationModule
模块随机取帧。
选取一个四角突起、中间凹陷的面片作为水花的模型是有原因的:如果把面片在垂直轴向上放大,模型的四角会被拉起,呈现一个类似圆柱形的形态;反之,在垂直轴向上缩小,模型的四角会随之降低,中间的凹陷保持不变,使整体更接近于圆锥形。当垂直轴向的数值到达 0 时,四角与中心不再有垂直位置的差异,圆锥变成了平面。所以,只要在垂直轴向调整模型的大小,加以其他轴向上的协调辅助,就能实现水花的不同形态。
我们已经在制作烟雾的时候使用过 SizeOvertimeModule
模块。勾选 SeparateAxes,在 X、Y 和 Z 轴上分别加以大小的修改。首先我们需要一个水花整体绽开的效果,通过之前对曲线数值的理解:可以在 X、Y 和 Z 轴上分别输入一个从 (0, 0) 到 (1, 1) 的直线来实现水花从小到大渐出的效果。我们需要的是水花绽开之后又塌陷成一个平面,所以需要对垂直轴向上的曲线做一些修改:在曲线的大约正中的位置右击选择 Create key frame 创建曲线上的新节点。有了新节点,可以把曲线最末端的节点拖拽到竖轴为 0 的位置,这样就形成了一条三角形的曲线。依次选取曲线上所有的节点,右击选择 Interpolation Mode -> Cubic,在节点之间进行插值,这样就得到了一条钟形的曲线。
在 SizeOvertimeModule
模块的作用下,水花绽开和塌陷的动画效果都已经出来了。
然而,这还不是最终的效果:目前水花的尺寸有些偏大,而且在刚绽开时也不够接近圆柱形。如果我们继续通过 SizeOvertimeModule
的曲线调节,不仅很难直观看到相应的结果,还有可能破坏已有的动画效果。还记得 StartSize
参数吗?我们之前用它无差别地改变雨点 Billboard 的大小来适应雨点贴图,现在也可以用它对水花的整体大小进行整体调整:勾选 StartSize3D
,在 X、Y 和 Z 轴上费别赋值,既可以打造理想的水花形态,也丝毫不会影响已经做好的动画效果。
最后,还是与之前一样,调整一下粒子的发射频率和生命周期(这将影响水花动画的速度),水花的制作也完成了。
火焰(复合粒子)
当我们使用粒子系统制作现实中的某个效果时,通常会发现仅仅使用单个粒子系统是不够的。现实中的各种效果往往是多种因素共同作用的集合,将这些细节都在视觉上还原出来,往往比不断打磨单个粒子系统更有一步到位的效果。在下面的例子中,我们将使用多个例子系统,实现火焰的效果。
首先需要一个火焰的精灵图集。我们使用的火焰图集是用程序纹理制作的。程序纹理的制作一般都遵循同样的逻辑:普通几何形状 -> 用不同类型的程序噪声纹理对几何形状进行变形,再用不同 Alpha 混合模式将不同的变形效果叠加在一起 -> 使用程序噪声纹理的参数使噪声产生位移,从而产生变形的动画效果 -> 用一个渐变依照明度染色。
导出图像序列之后,依照之前的流程,将图像序列转换为一张精灵图集。将精灵图集导入引擎,制作相应的粒子材质。粒子材质默认的 Add 模式非常适合火焰的制作。
粒子系统方面,选取锥形的发射器,将 Angle
和 Length
参数都设为 0,使发射的粒子不会向外飞散,并且保证粒子都在同一水平面上射出。火焰粒子应该排列较为密集,大致以稍低于气体上升的速度上升,但火苗只能蹿升到一定的最高高度,说明粒子的生命周期比较短。所以 StartSpeed
可以取略小于 1 的数值,StartLifetime
也需要较小的数值。
火焰通常看上去整体呈钟形,这意味着粒子在刚发射时的尺寸比较大,随着生命周期逐渐变小。我们之前遇到的大多数粒子案例,都是发射时尺寸较小,随生命周期逐渐增大的“上坡”曲线。对于火焰,可以在 SizeOvertimeModule
模块中使用一个“下坡”曲线。
将材质赋予粒子系统,开启 TextureAnimationModule
模块,之前我们已经使用过了 Curve
和 TwoConstants
两种数值类型。TwoCurves
相当于它们二者的结合:粒子会在同一个生命周期中的时间点在两条曲线的数值之间随机取值。我们可以将 FrameOverTime
参数设定为 TwoCurves
类型,并给予一条“上坡”曲线和一条“下坡”曲线,得到的结果就是有的粒子以正序播放精灵图集,有的以倒叙播放,有的取两者的中间值。我们之前还使用过 StartFrame
参数,它决定了精灵图集播放的起始帧,使用一个最大值和最小值,可以让粒子随机从图集中选择一帧开始播放。
与烟雾一样,可以使用 ColorOverLifetimeModule
模块,使用 Alpha 值将刚发出和即将消失的粒子隐藏,使火焰的整体形态更加平滑。使用渐变中的 RGB 数值,可以为火焰的某一个区间的颜色进行微调,丰富火焰的颜色和明度变化。
粒子的飞行轨迹、随机性和整体形态都有了,我们只需要和之前一样,调整粒子的频率和密度,增添一些旋转和大小的随机性,火焰的效果就实现了。
对于许多项目来说,火焰的制作到这里就可以结束了。然而,虽然我们的粒子看上去比较像火焰,但单独放在场景里还是难免有假的感觉。在这种情况下,我们不需要考虑增加渲染的复杂度,去追求更高的粒子数量,反之,可以打造一些在现实中会伴随粒子出现的细节,比如:火焰一定伴随着烟雾的产生,并且会有燃烧不完全的火星飞出;降雨在比较强烈时,会在地面附近形成一层较薄的水蒸气等。
烟雾我们已经制作完成了,火星的制作也并不复杂:火焰的精灵图集已经有了,只需要制作符合火星飞行规律的粒子即可。
我们将在此基础上修改来实现火星的效果。将火焰粒子系统复制一份,火星可以继续使用火焰的精灵图集,我们可以稍微调整 ColorOverLifetimeModule
的渐变颜色,让它更鲜明一些。
火星的最大特征在于:
尺寸较小,
StartSize
参数或SizeOvertimeModule
模块的取值应该比较小,但仍然肉眼可见;飞行轨迹不同,火星是燃烧不完全的细小固体颗粒,不应该像火焰一样集聚在一起,相反,在热能的作用下应该有向外飞出的趋势。飞出后受其自身质量的影响,应该有下降的趋势。
我们在制作火焰时选择的锥形发射器,本身就是在以锥形方向发射粒子的,只需要把 Angle
参数恢复为一定的数值给锥形一定的角度即可。位于发射器属性最下方的 RandomDirectionAmount
、RandomPositionAmount
和 SphericalDirectionAmount
参数我们之前介绍过,它们可以为粒子的发射增加位置和方向的随机变化。除此之外,现实中的火星有些可以弹射的很高,有些只能飞到较低高度,这个区别其实就是粒子飞行速度的区别,可以用 StartSpeed
参数轻松实现。最后,我们需要制作火星受重力影响下落的动能,在制作烟雾的过程中我们使用了 ForceOvertimeModule
模块为烟雾的漂浮提供了动能变化,在普通粒子的基本参数中有一个方便的 GravityModifier
参数,能为粒子赋予重力的属性。当它的数值等于 0.98 时,粒子与绝大多数现实中的物体一样,发出后会直接落向地面。因此我们只需要给火星一个非常小的 GravityModifier
数值,使他能够飞行的同时,保持受重力影响的动能。
火星制作完成之后,将火焰、火星和烟雾打成一组放置在场景里,当然也不要忘了放上一盏火红色的球形灯,将火焰周遭照亮。做完这些,火焰的可信度是否提升了不少呢?
喷火和烛火(粒子的变体)
我们已经完成了一个完整的火焰粒子系统,然而在项目中虽然火焰用的地方不少,但端端正正的一团篝火的使用机会还是比较有限的。如果我们需要制作火焰的其他形态:比如喷射的火焰、蜡烛的烛火呢?
喷射的火焰看上去很复杂,但与我们之前制作的粒子并无差别:首先是形态,我们对粒子的发射速度、密度、粒子的大小变化等要素的掌控已经非常熟悉了。这种喷涌而出的火焰如何制作,其实一定程度上我们已经解答了:在制作篝火时,我们基于制作烟雾的经验,给予 SizeOvertimeModule
一个“下坡”的曲线使粒子随生命周期变小,现在只需要反其道行之,给予 SizeOvertimeModule
一个“上坡”的曲线即可得到发射后不断膨胀的火焰粒子,这与对烟雾粒子的大小控制是一样的。火焰喷射的强劲动能可以理解为粒子发射的速度,StartSpeed
仍然是不二选择。
喷射产生的烟雾,在遵循着喷射的方向飞行一段距离之后,因为自身较轻的质量应该向上飘向空中。我们对粒子发射后飞行轨迹的控制已经很熟悉了,ForceOvertimeModule
将帮助我们实现其效果。在制作火星时我们介绍了 GravityModifier
参数,将 GravityModifier
设为负值也能得到反重力的效果,使粒子向空中飘去。除此之外,VelocityOvertimeModule
模块可以为粒子的发射提供一个具体数值和方向的加成,如果需要粒子飞行中能够一定程度上抵抗 ForceOvertimeModule
和 GravityModifier
的影响,则可以开启它。与之相对的,LimitVelocityOvertimeModule
模块能够提供一个反作用于 VelocityOvertimeModule
的加成,它会优先作用处于生命周期末尾的粒子。与 VelocityOvertimeModule
相结合使用,由此,我们可以做出粒子先受喷射的动能影响飞行,然后动能耗尽,粒子只受重力和 ForceOvertimeModule
影响的过渡变化。
至于火星,在喷射之后首先会遵循着喷射的方向飞行,但受到烟雾的影响,它落向地面的趋势不明显,反而会一部分被烟雾带到空中。使用上述的模块配合,我们同样可以指定火星的飞行受力和轨迹。
最后,ColorOverLifetimeModule
依然是粒子整体呈现的重要一环,我们可以将渐变的左侧,也就是粒子刚射出部分的颜色加以调整,使其呈现一种蓝绿色,模拟部分化学成分在极高温下火焰的颜色。不仅是颜色变化,火焰的 Alpha 值同样非常重要,火焰粒子材质使用 Add 模式,我们可以尝试在渐变中加入更多偏暗的颜色节点,在产生颜色变化的同时,让 Alpha 的融合更加自然。
烛火最终效果
相较于喷火的激烈,烛火则比较容易被人忽视。在一些项目中(其中不乏国外的经典之作)甚至直接把缩小版的篝火作为烛火使用。虽然理论上烛火和普通的篝火没有什么区别,然而从视觉的角度,烛火有它独有的特点:
颜色较亮,只有尾部会呈现部分火红色,主体部分近乎于白色;
整体形态比较统一,没有复杂的形态和细节变化,但仍然具有火焰的跳跃感;
我们仍然可以把缩小后的篝火作为起点。首先,既然烛火的形态比较统一,那么火焰的精灵图集就没有必要登场了,直接使用一个静态的圆形渐变,或者在材质 MainTexture
参数的下拉菜单中选择引擎自带的 Default-Particle
贴图。既然使用了圆形贴图,粒子旋转的变化也不再有必要了。与烛火相比,篝火的尾部有许多细小的火苗,我们之前一直使用 ColorOverLifetimeModule
将头部和尾部的粒子隐藏,同理,我们在使用 ColorOverLifetimeModule
时可以更激进一些,将隐藏的范围进一步扩大,直至篝火尾部的所有火苗都隐藏起来。这样一个浑然一体的烛火轮廓就产生了。最后,烛火的颜色变化同样可以通过 ColorOverLifetimeModule
实现,在制作喷火时已经使用了这种操作:将渐变的左侧设为蓝色,右侧设为火红色,分别为烛火的头部和尾部赋予颜色。一个带有颜色变化,清晰而干净的烛火就完成了。
今天我们通过 Cocos Creator 的粒子系统,实现了烟雾、星光、降雨、火焰、喷火和烛火的粒子效果呈现,并且将粒子系统中主要的功能模块和制作方法介绍了一遍。你会发现:自然界中的种种效果虽然看上去变化无常,实际上都有一定的规律可循,添加一定的随机变化,加以一定数量的粒子叠加,我们可以制作出各种令人信服的粒子效果特效。