在上一篇《Cocos Creator 渲染实战:地编篇》中我们主要介绍了 3D 户外场景的搭建,本文中我们将了解粒子系统的使用方法和一些典型自然效果的实现,制作一个粒子效果的通常流程是:

  • 使用贴图或模型决定每个单独粒子的形态,创建相应的粒子材质;

  • 创建粒子系统,决定粒子的发射频率、密度和飞行速度;

  • 使用动力学模块添加动态变化,模拟物理效果;

  • 将粒子系统移动到场景中合理的位置。

接下来让我们从基础说起。

PS. 本文将分为基础-烟雾(普通粒子)-性能优化-星光(动画粒子)-降雨(3D 粒子)-火焰(复合粒子)-喷火和烛火(粒子的变体)几个部分,篇幅较长,建议先马后看。

基础

首先我们需要在场景中创建一个新的空节点:在层级管理器中点击左上角的加号按钮,或在层级管理器中任意空白的部分右击选择 Create -> Empty Node。选择新建的空节点,在属性检查器末尾点击 Add Component,选择 Effects -> ParticleSystem,为空节点增加粒子模块。

粒子是一种从一个固定的发射点不断向外发射可渲染图形的渲染系统。它大致由发射器、粒子和渲染器三个主要功能模块组合而成。其中,我们可以通过发射器的参数控制粒子在场景中射出的位置,粒子生成的频率和随机性、每个粒子射出后的生命时长等等。通过粒子相关的功能模块我们可以控制每个粒子射出后的位置、大小、颜色等属性的变化。通过渲染器我们可以为每个粒子赋予贴图,决定粒子系统与整个场景的混合模式,粒子与摄象机的坐标关系等等。

在默认情况下,粒子系统只要在场景中被激活就会开始生产粒子,我们不需要任何手动的方式启动它。当我们选中了一个带有粒子系统的节点之后,在场景编辑器的右下角会出现粒子效果的预览控制选项,这包括开始、暂停、重置、停止和播放速度等。我们完全可以把粒子系统看作一个会自己产生动画的渲染系统,而这些预览控制项与我们熟悉的动画控制系统也没有本质区别,我们可以通过它们控制粒子系统在场景编辑器中的预览效果。

可以看到,默认的粒子系统会以其父节点的位置为发射点,不断朝一个方向发射白色的半透明正方形图形。因为发射的频率较高,发射出来的粒子也没有丝毫的位移和动能的变化,所以发出的粒子连成了一条白色的直线。这与我们想象中的粒子效果相去甚远,我们首先要做的是弄清楚粒子是如何发射的。

现在的发射频率无疑是太高了,我们首先需要降低粒子产生的数量。选中粒子系统,在属性检查器中将 RateOverTime 参数从 10 改为 1。在场景编辑器中,按下左下角播放控制的重置按钮,使粒子系统从头开始重新渲染。

修改后,粒子发射的频率小多了,目测观察,大概是每秒发射一个粒子的频率。另外,粒子能够飞行的最大距离并没有变化,换句话说:粒子连在一起形成的“直线”的长度并没有变化。

目前单个粒子飞行的速度还是有些太快了,我们可以试着把 StartSpeed 参数从 5 改为 2.5。

粒子的飞行速度减小了一半,与此同时,粒子能够飞行的最长距离也减少了一半,因为粒子发射的频率并没有变化,所以在同样的时间段内发射的粒子的数量并没有减少,相应地前后两个粒子之间的距离缩小了。

虽然粒子飞行的速度降低了,但我们仍然希望得到与之前一样的最大飞行距离:我们可以将 StartLifetime 参数,从 5 改为 10。

粒子的最大飞行距离恢复到了之前的程度,同时每个粒子飞行的速度和粒子之间的距离也维持了我们上次修改的水平。但相应地同时存在的粒子数目增加了:从我们之前观察到的大约 5 个,增长到了大约 10 个。

那么,如果把 StartSpeed 从 2.5 改回默认的 5,又会怎样呢?

我们可以看到,因为 RateOverTimeStartLifetime 都没有变化,所以我们仍然保持了粒子总数为 10 个的状态,但由于 StartSpeed 增加了一倍,因此在相同的时间里,粒子能够飞行的距离增长了一倍。换句话说:粒子之间连线的长度增加了一倍。

总结起来,我们似乎能够在 RateOverTimeStartSpeedStartLifetime 这三个参数之间,观察到一定的规律:

  • RateOverTime 控制每秒发射粒子的个数;

  • StartSpeed 控制粒子被发射出后飞行的速度;

  • StartLifetime 控制粒子的生命周期,即粒子被发射出后能够存在的时长。当生命周期结束之后,粒子会自动从场景中消失。

不仅如此,从上面的实验当中,我们还能推导出当前同时存在的粒子个数、粒子能够飞行的最长距离和两个相邻粒子之间的距离的取值逻辑:

  • 当前同时存在的粒子个数,大概等于每秒发射粒子的个数与粒子生命周期的乘积,即 RateOverTime * StartLifetime

  • 粒子能够飞行的最大距离,大概等于粒子飞行的速度与粒子生命周期的乘积,即 StartSpeed * StartLifetime

  • 降低相邻两个粒子之间的距离,或增加粒子的密度,可以在粒子能够飞行的最大距离( StartSpeed * StartLifetime )不变的情况下,增加每秒发射粒子的个数(RateOverTime),反之同理。

掌握了这些,我们就可以利用粒子飞行的最大距离和粒子的密度,对粒子系统的整体造型进行一定的把控了。除此之外,我们已经能够推算出当前粒子系统中的粒子数量,这将帮助我们最大程度优化粒子系统的执行性能。

对粒子的发射原理有了一定的了解,我们还需要给粒子特定的造型。这个白色的正方形显然已经不适用了,我们需要为粒子赋予一个具体的材质。

资源管理器中点击左上方的加号按钮,或在资源管理器的任意空白区域右击,选择 Create -> Material,新建一个空的材质文件。粒子系统需要为其专门准备的 Shader,所以在新建的材质参数中,我们需要将 Effect 参数选择为 builtin-particle

粒子材质的使用非常简单,只需要将相应的贴图赋予 MainTexture,然后依据需要使用 TintColor 参数对颜色和 Alpha 进行微调即可。保存对材质的修改,回到粒子的属性检查器中,将粒子材质拖拽到 Renderer 标签下的 ParticleMaterial 参数上。

在默认情况下,粒子系统的渲染方式与我们前文提到的 Billboard 的渲染方式是相同的,都是将 2D 的像素以永远正对摄像机的方式渲染到 3D 场景中。这项设置我们可以在粒子系统 Renderer 标签下的 RenderMode 参数进行选择。我们在前文中提到过使用 Billboard 配合一张渐变贴图制作体积光的假象,同样的方法我们可以使用在粒子系统上:粒子系统经常用作模拟的烟雾、火焰、光斑效果,实际上都是使用一张平面的贴图,来模拟现实中有一定体积的效果。因此,Billboard 也是粒子最常见的渲染方式。

那么,自然界中的各种效果又是怎样使用粒子系统实现的呢?我们先从烟/雾说起。

烟雾(普通粒子)

烟雾最终效果

既然我们的目标是制作烟雾,那么我们首先需要的一张烟雾的贴图素材。

素材的明度、颜色等都无关紧要,因为我们只需要素材的一部分。首先使用 Photoshop 等 DCC 去除素材的颜色,仅保留明度的信息。之后调整色阶,确保背景为纯黑色。将素材另存为贴图导入到引擎中,赋予到我们刚创建的粒子材质上。

使用了烟雾的素材之后,原本半透明的正方形,变成了半透明的贴图面片,通过粒子材质的 TintColor 参数为贴图赋予一定颜色,因为 Billboard 渲染的缘故,面片始终保持正对摄像机,乍一看确实有些许带有体积的团状物的意思。

不仅如此,你大概已经发现了:贴图的黑色背景并没有被渲染出来,而且贴图面片之间也产生了叠加的关系。这是因为粒子的材质默认使用 Add(相加)的 Alpha 混合模式。引擎会依据渲染出来的粒子像素的明度作为不透明度,将粒子的像素直接以线性相加的方式叠加到 Frame Buffer 上。这种效果与我们在 Photoshop 中将图层的混合模式选为“线性减淡(添加)”是一样的。粒子材质的 Alpha 混合模式由 Technique 参数控制,在默认的 Add 模式下,使用的粒子贴图不需要考虑其透明程度,只需要确保我们希望是透明的部分在贴图中是纯黑色就行。即便是肉眼看不出区别的明度极低的深灰色,也会在 Add 模式下留下贴图边缘的痕迹,导致“抠图抠不干净”的问题出现。同理,我们不用在不透明的部分包含任何颜色信息,因为我们可以直接通过材质的 TintColor 参数调节颜色,如果贴图本身已经包含了颜色信息,粒子材质就会产出两种颜色的混合,让精确控制粒子颜色变得很困难。

Add 模式看上去很好用,但会产生一个问题:如果我们要制作黑色的烟雾呢?如果把 TintColor 参数调为黑色,你会发现粒子完全消失了,这是因为贴图所有的像素都被设为了黑色,因此被 Add 模式视为完全透明了。

为了解决这个问题,我们首先要对贴图进行一些修改。回到 Photoshop,将之前已经做好的黑白贴图全选复制,将其粘贴为一个新的 Alpha 通道,建立一个新的纯白图层,从新建的 Alpha 通道中选择像素并生成遮罩,另存为一张带 Alpha 通道的格式(如 .png )。

将新贴图导入引擎赋予给粒子材质,同时,将 Technique 参数选为 1-alpha-blend。这种模式与 Add 模式相反:只有半透明的像素会被叠加到 Frame Buffer 上,而不透明的像素则会保留自身的颜色。所以在使用这种混合模式时,我们需要一张有明确 Alpha 通道的贴图,同时,因为不透明的像素颜色得到了保留,我们可以在 TintColor 参数中使用黑色,这不会导致粒子的消失。

现在,我们的粒子已经“长”的比较像烟雾了,下面我们需要做的是使用粒子系统的动力学模块,让粒子动起来更像烟雾。

目前,粒子系统以完美的匀速生成出一摸一样的粒子,每个粒子以完美的匀速水平运动,并在同一个时间点消失。我们需要做的就是打破这种完美的状态,为粒子系统代入一定的随机性。

首先,对于烟雾来说,每一个粒子的大小可以更大些,我们可以在 StartSize 参数中输入一个更大的数值来实现。

更大的粒子更能体现出烟雾的体积感,但目前每个粒子都是一摸一样的,能否让它们产生不同的旋转角度呢?

使用 StartRotation 参数可以为粒子赋予旋转角度,输入一个数值,得到的结果是每个粒子都相应地改变了角度,每个粒子仍然是一摸一样的。有没有可能在每个粒子生成时,给它们分别获得一个随机的旋转角度呢?

点击 StartRotation 参数末尾的倒三角,可以得到一个数值类型的菜单。目前已选择的是 Constant,表示 StartRotation 参数只接受一个常量数值。在菜单中选择 TwoConstantsStartRotation 参数发生了变化,我们需要输入 ConstantMinConstantMax 两个数值,即一个最大值和最小值。

现在,每一个粒子在生成时,都被赋予了一个随机的旋转值,而这个旋转值是由我们定义的最大值和最小值的区间决定的。当然,区间的取值范围越大,随机的程度也相应越大。

方法有了,我们可以如法炮制,为粒子的大小(StartSize)、飞行速度(StartSpeed)和生命周期(StartLifetime)加入随机性。

现在我们有了一堆旋转随机、大小不一、飞行速度和最大距离各异的粒子。然而,它们看上去更像几块漂浮的棉絮,而不是浑然一体的流体。这是因为目前生成的粒子数量太少了,我们需要更多粒子重叠在一起的感觉。

烟雾的效果已经接近了,但是粒子仍然是水平角度发射的,我们能否做出烟雾飘向空中的效果呢?

我们在一开始就用一个空节点作为粒子系统的父节点,通过旋转这个节点来实现垂直的粒子发射方向当然是可行的,但是这样做会改变粒子的世界坐标系统,当粒子系统比较复杂时容易产生方向的混淆。

在粒子系统的属性检查器下方有若干可以勾选的模块。勾选 ShapeModule 将开启发射器相关的参数设置。

粒子的发射器分为方盒形、圆形、锥形、球形和半球形五种形态,它们决定了粒子发射的范围和方向,粒子的发射只能发生在发射器的范围之内,我们可以把粒子与不同的模型结合,利用不同发射器形状的特点,确保粒子不会在不该出现的地方发出。发射器包含位置、旋转和缩放的参数,可以更改发射器在场景中的位置和朝向,同时又不影响整个粒子的坐标系统与世界坐标对齐。在发射器模块底部有 RandomDirectionAmountRandomPositionAmount 参数,能够让粒子发射的方向和位置在发射器的基础上增加一定的随机性。而 SphericalDirectionAmount 参数能够让粒子在无视发射器的情况下,增加向四周所有方向发射的随机概率。

只需要把发射器延 X 轴旋转 90 度,即可改变粒子的发射方向。

现在的整体效果看上去可以接受,但每个粒子在飞行的过程中是僵直不动的,单独观察,还是可以看出贴图的感觉。

除了在粒子的发射过程中加入随机性之外,在粒子被发射后飞行过程中我们同样可以加入动态的变化。

勾选 RotationOvertimeModule 开启该模块。这个模块的功能是让每个粒子在飞行的过程中每秒依据一定的角度旋转。当然,也可以为它的参数赋予一个随机值的区间,让每个粒子旋转都有细微的差别。

添加了旋转的动态变化之后,贴图的 2D 观感进一步减弱了,粒子的旋转也能模拟出气体蒸腾的感觉。

单个粒子的处理已经完成的差不多了。我们仍然需要考虑的是整个粒子系统或整个烟柱的姿态。

现在的烟柱从上到下是一样大的,换句话说:粒子从出生开始一直到生命周期结束,一直是一个大小。这种效果显然很不自然,尤其是当我们要制作烟雾从一个较小的出气口喷出的效果的时候。

勾选 SizeOvertimeModule 开启该模块。与 RotationOvertimeModule 不同的是,这个模块的参数只是让每个粒子依照 StartSize 已经设定的大小按照一定数值倍数缩放,即便给予它最大值和最小值,也是让每个粒子在区间中随机取值缩放。烟柱整体等大的问题并没有解决。这时就需要我们调用另外两种数值类型:CurveTwoCurves

选择 Curve,点击参数的输入框,弹出曲线编辑窗口。

曲线的数值关系很容易理解:曲线的横轴代表着时间,也就是单个粒子的生命周期;曲线的竖轴代表数值,既然我们在修改 SizeOvertimeModule 的数值,那么横轴当然代表大小缩放的倍数。默认情况下,曲线是一条水平直线,这与我们输入一个常数数值的效果相同:粒子从出生到生命周期结束,都使用同样的缩放倍数。我们的目标是一个上大下小的烟柱,换句话说,粒子应当在出生时较小,随着生命周期逐渐放大,在生命周期结束时达到最大。用曲线翻译这种逻辑:我们要的是一条从左往右“一路上坡”的曲线。

在曲线编辑窗口左侧 Preset 标签下快速选取一个符合我们要求的曲线,最简单的当然是从 (0, 0) 到 (1, 1) 的直线,而它所产生的效果当然也是粒子从新到旧大小线性递增,形成近乎锥形的烟柱。

虽然线性的曲线大概可以接受,但是为了更自然的效果,我们还可以在曲线的基础上机型细微调节。点选曲线上的任意一个锚点可以拖拽锚点在曲线上的位置,在锚点上右击,选择 Interpolation Mode -> Cubic 可以改变曲线的插值模式,使用贝塞尔曲线来产生圆滑的数值过度。在曲线线段上任意部分右击,选择 Create key frame,可在曲线上插入一个新的锚点,在锚点上右击选择 Edit,可手动输入锚点的坐标数值,输入后单击锚点完成确认。最后,在锚点上右击选择 Delete,可删除锚点。

熟悉了这些操作,我们可以使用曲线打造各种各样的参数动画效果。简单而言:这些参数动画都是针对每个单独的粒子的,动画的时长就是粒子的生命周期,如果你的粒子的生命周期很短,这些参数动画再复杂,也会相应地一瞬而过。

现在,我们已经了解了曲线数值类型。在继续下面的内容之前,不妨先来一个小 quiz:我们之前介绍了 RotationOvertimeModule 的功能模块,如果在 RotationOvertimeModule 输入曲线数值,会出现什么效果呢?

我们提到过:RotationOvertimeModule 的功能是让每个粒子在飞行的过程中每秒依据一定的角度旋转。所以它的参数数值实际相当于旋转的速度而非位移值,因此如果给予它曲线数值的话,会出现粒子随着生命周期旋转越来越快或越来越慢的效果。

现在烟柱的“形”也有了,我们还需要处理烟柱的“态”。现实生活中一条笔直的烟柱是几乎不存在的,烟柱收到气流的影响一定会形成一定的偏转。

我们可以使用 ForceOvertimeModule 为飞行中的粒子增加一个力的影响。虽然烟雾使用的是 2D 的贴图,但是粒子都是在 3D 的空间中发射的,所以也可以从 x, y 和 z 三个轴向分别向粒子施加力的影响。同样的,我们可以使用曲线数值代替常量数值,为其增加动态的变化。

做到这一步,我们终于迎来了烟雾的最后一个模块,可能也是最重要的一个模块:颜色变化。

先来观察几张参考图:依据燃烧的杂质不同,火焰产生的浓烟在接近火焰的部分颜色更深,接近于黑色,随着烟雾的飘散慢慢变成深灰色和浅灰色,直至完全消失。

我们之前已经使用粒子材质的 TintColor 参数实现了不同颜色的烟雾。然而现在需要调整的是烟柱整体的颜色变化,修改 TintColor 只会对所有粒子的颜色无差别地更改,所以在粒子材质中,仍然使用纯白色。

勾选 ColorOverLifetimeModule 开启该模块。这个模块与我们之前接触的模块很相似,它的参数默认接收一个常量颜色,使用常量颜色与更改粒子材质颜色的效果相同,将产出一个全部粒子无差别染色的烟柱。ColorOverLifetimeModule 也可以接收两个常量颜色(TwoColors),这与我们之前接触的 TwoConstants 也没有本质区别,每个粒子将会在两个常量颜色之间随机选择颜色,形成一条颜色斑驳的烟柱。我们今天要使用的,是第三种数值类型 Gradient

点击参数的输入框,弹出颜色渐变编辑窗口。

颜色渐变与我们之前接触的曲线的逻辑时一样的,从左到右,渐变的整个长度相当于粒子的整个生命周期,渐变上的 Alpha 和颜色相当于粒子在相应的生命周期应该具有的 Alpha 和颜色。颜色渐变的编辑非常直观,与在 Photoshop 中制作颜色渐变是一样的:上方的滑块控制 Alpha 值,可以点选滑块的任意部分生成一个新的节点,选择节点,在下方的颜色选择器中为它赋予一个 Alpha 值。下方的滑块控制 RGB 值,同理,点选任意部分生成节点,赋予 RGB 值。

目前粒子在生成和消失的时候没有任何渐进渐出的效果,粒子会瞬间凭空出现,生命周期结束后又瞬间凭空消失。发射时由于 SizeOvertimeModule 的控制粒子非常小,因此影响不大,但在粒子消失的时候这种生硬的消失非常影响观感。ColorOverLifetimeModule 非常适合解决这个问题,我们只需要创建一个头部和尾部 Alpha 值都为 0 的颜色渐变,就可以让刚发射出来和即将消失的粒子变为全透明,只保留中间的主体部分。在此基础上,我们依据从参考图中观察到的颜色变化,在渐变上创建几个不同明度的灰色节点,就可以制作出由暗渐渐转淡的颜色变化效果。

做到这里,烟柱已经成型了。在结束制作之前,我们最后根据细节来对参数进行一次微调。经过上面的流程,相信你对达到不同效果需要调节的参数,已经熟记于心了:

  • 烟雾飞行的太快或太慢?调节 StartSpeed

  • 烟柱太高或太低?确定 StartSpeed 的基础上,调节 StartLifetime

  • 烟雾太稀薄或太厚重?确定 StartSpeedStartLifetime 的基础上,调节 RateOverTime,也可以调节粒子材质 TintColor 的 Alpha 值;

  • 让烟雾从细小的出气口喷出,或从一篇区域内喷出,或无差别朝四面八方喷出?调节 ShapeModule

  • 烟柱太细或太散?调节 SizeOvertimeModule

  • 烟雾看上去太死板或太乱?调节 RotationOvertimeModule

  • 烟雾飘散的方向不对?调节 ForceOvertimeModule

  • 烟雾的颜色不够丰富?调节 ColorOverLifetimeModule

性能优化

影响粒子系统性能的最大因素,无疑是同时同屏的粒子的数量。只看我们目前的烟雾粒子可能对性能的影响没有什么感觉。但如果是一个粒子数量非常多,飞行的轨迹非常复杂,而且每个粒子是 3D 模型的粒子系统,那么性能的影响就很难被忽视了。

对于同时同屏的粒子的数量而言,影响最大的是 Capacity 参数。它的作用逻辑是:当粒子系统中同时存在的粒子数量高于 Capacity 所指定的数值时,粒子系统会暂时停止发射粒子,等待现有的粒子生命周期结束,直到当前的粒子数量降到低于 Capacity 数值时,粒子的发射才会依照正常情况恢复。所以当我们调高 RateOverTime 参数到一定程度时,会出现粒子发射“断断续续”的情况,这正是 Capacity 参数在发挥作用。

因此,为了获得最佳的性能,我们除了要在效果能接受的情况下尽量降低粒子发射的频率(RateOverTime)之外,还需要将允许同时存在的粒子个数(Capacity)控制在最小的范围内。所幸的是,同时存在的粒子个数可以通过 RateOverTime * StartLifetime 推算出来。因此我们只需为 Capacity 取一个略大于 RateOverTime * StartLifetime 的数值,确保 Capacity 不会导致粒子暂停发射,就能在不影响效果的前提下保证粒子系统的执行效率。

除此之外,我们还可以开启粒子系统的 RenderCulling 功能。勾选 RenderCulling,按下 Generate bounding box,引擎会根据粒子可能会飞行到的区域形成一个边界盒。在开启 RenderCulling 的情况下,如果边界盒没有出现在摄像机可观察到的范围中,则整个粒子系统不会被渲染;当边界盒重新回到摄像机的视野内,粒子渲染会重新开启。边界盒的大小可以手动通过参数进行调节,开启 RenderCulling 可以避免在粒子没有被观察到的情况下,消耗无意义的渲染资源。

星光(动画粒子)

星光最终效果

我们的第一个粒子系统已经完成了,借助烟雾效果的实现,我们已经熟悉了 Cocos Creator 粒子系统的基本逻辑和一般效果实现的方法。对于烟雾来说,效果的关键在于粒子的渲染方式和动态的变化关系,每个单独的粒子其实只是一张静态贴图,而静态贴图是完全没有变化的。

当然,静态贴图不可能满足我们对粒子效果的所有需求,如果需要每个单独粒子都会带有动画效果呢?

Billboard 的渲染方式能够很理想地把 2D 贴图作为粒子融合到 3D 场景中。我们可以使用同样的方法把动态的贴图导入引擎供粒子系统使用,那么问题是:如何将动态形式的贴图导入引擎呢?

无论是视频格式还是 .gif 文件,本质上都是许多帧静态像素图的集合,当程序以一定速度将这些像素图依顺序播放出来的时候,就形成了动态的画面效果。在影视后期特效领域,图像序列( Image Sequence )依然是一种常用的工具。所谓图像序列,就是把一段动画或视频的每一帧都以某种格式的静态图片渲染出来,以便在 DCC 中重新组合和播放。目前绝大多数主流的视频编辑软件、后期处理软件和 3D 设计软件,都支持渲染图像序列。

图像序列通常会生成大量的图片文件。比如一段 1K 分辨率( 1920 × 1080 )以 30 FPS 播放的 1 分钟视频,就会导出 1800 张单独的图片,其总共的数据量甚至比同样分辨率和帧率的任何视频文件还要大。游戏引擎通常对资源的容量非常敏感,图像序列对其而言显然是不合适的。

在 2D 游戏的领域,我们接触过精灵图集(Sprite Sheet)的概念,精灵图集与图像序列类似,它同样是把动画的每一帧都单独存储为静态图片,不同的是,精灵图集会把所有的静态图片集合到同一张贴图上。遗憾的是,目前市面上可供美术直接使用的支持导出精灵图集的 DCC 非常少,除了 Adobe Animate(当年的 Flash)可以说寥寥无几。那么,如果能够把图像序列转换为精灵图集,是否就能打开新世界的大门了呢?

下面,我们就来看一下将星光作为粒子导入 Cocos Creator 的流程。

星光的效果是在 After Effects 中使用红巨星插件制作的,这段简单的闪烁动画时长是 2 秒,帧率是 30 FPS。我们首先要做的,是将其导出为图像序列。

渲染完成后,可以在存储目录中找到图像序列包含的图片。下面需要做的是把这些图片合拼到一张贴图上。

诚然,我们可以打开 Photoshop,在一张足够大的画布上手动把它们拖拽到一起。然而这样操作毕竟费时费力,而且如果遇到帧数更大、时长更长的动画,图像序列中的图片数量会相应陡增,手动拖拽就更行不通了。

在这里我们借助国外的一款免费软件 Free Texture Packer 帮助我们完成图片的堆叠,Free Texture Packer 是一款专门为 Cocos、Unreal Engine、Phaser 等游戏引擎设计的精灵图集生成工具,它提供跨平台支持,并且完全开源。

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

WidthHeight 参数中输入理想中的精灵图集分辨率大小,如果当前导入的图像序列中的图片太多,可能会出现一张精灵图集放不下的情况,软件会自动将放不下的部分放入第二张图集。这当然不是我们想要的结果。调整 WidthHeight 的数值,尽量充分使用一张图集的空间,同时保证所有的图片都能够放入一张图集中,我们不需要保证 WidthHeight 的数值一样或 POW 数值,因为在图集生成后,可以再用 Photoshop 打开整体缩放为我们理想的大小。

设置完成后,在 Save path 输入存储目录,点击 Export 即可生成图集。

下面就是把精灵图集应用在粒子系统上了。将图集作为一张普通贴图导入 Cocos Creator 中,创建一个新的粒子材质,将导入的图集直接赋予粒子材质。

新建一个节点,添加新组件并选择 Effects -> ParticleSystem。这次,直接开启 ShapeModule 模块,选择一个球形的发射器。可见,在默认情况下,粒子会从球形的各个方向随机发出。

我们希望的效果是星光在模型表面闪烁,也就是说,粒子生成后不应该飞出去。回忆上面在制作烟雾过程中我们掌握的参数细节:把 StartSpeed 设为 0。

StartSpeed 为 0 时,粒子生成后不会向外飞出,而是会停留在诞生的位置。为了保证粒子只会在发射器的外部生成,还可以在 ShapeModule 模块下的 EmitFrom 参数下选择 Shell

现在可以把粒子材质赋予粒子系统了。将使用了精灵图集的材质拖拽到 Renderer 标签下的 ParticleMaterial参数下。

粒子的白色正方形变成了一堆密集的亮点。我们之前已经提到了:粒子材质默认使用 Add 的 Alpha 混合模式,可以非常容易地混合黑色背景的贴图。线性叠加的方式也符合现实中光的线性叠加特性。至于为什么是密集的亮点也不难理解:精灵图集表面上看上去确实是密密麻麻的贴图堆放在一起。我们需要做的是让粒子系统将精灵图集识别为动态的效果。

首先,勾选 TextureAnimationModule 开启相关模块。精灵图集是图像序列的集合,所以需要告诉模块它是怎样集合的:观察精灵图集,记下它的行数和列数,分别输入 NumTilesXNumTilesY 中。

接下来需要让精灵图集动起来,这将由 FrameOverTime 参数实现,我们在前文中中提到过参数的曲线数值:曲线的横轴为粒子的整个生命周期,曲线的竖轴为数值大小。因此,需要为 FrameOverTime 输入一个曲线数值,由曲线的取值实现动画的效果。最简单的方式当然是使用从 (0, 0) 到 (1, 1) 的直线,这意味着随着粒子生命周期的流逝,线性地使用精灵图集中的每一张图像序列,这种方式与我们常见的视频播放是一样的。

那么,如果使用从 (0, 1) 到 (1, 0) 的直线呢?这意味着从精灵图集中的最后一张图像序列开始,线性地使用前一张图像序列,和视频倒放的效果是一样的。

如果不用直线,使用带有曲度的贝塞尔曲线呢?其效果也很好理解:“上坡” 意味着正序播放,“下坡”意味着倒序播放,“上/下坡”的幅度高于 45 度,意味着高于正常的帧数(“快进”)播放,反之则意味着低于正常的帧数(“慢进”)播放。

我们已经告诉了模块“播放”那些图像序列以及以怎样的方式“播放”,还需要告诉模块“播放”多少次。将数值输入到 CycleCount 参数中,如果数值为 0,则精灵图集不会播放,粒子会停留在序列的第一帧上;如果数值大于 1,则粒子在生命周期的过程中会循环播放相应的次数。

完成设置后,我们就成功将 After Effects 制作的效果,以图像序列的形式,以精灵图集的介质,导入到 Cocos Creator 中作为粒子了。你会发现每个星光播放的速度好像有点慢:在导出图像序列的时候动画只有两秒。其中的原因我们在前面也提到了:粒子会使用它的整个周期播放图像序列,相当于把序列中的动画拉长或缩短到了与粒子生命周期同样的长度。我们只需要相应地改变粒子的生命周期(StartLifetime),或者增加生命周期中播放的次数(CycleCount)即可。

最后,运用在制作烟雾的过程中掌握的其他模块使用方法,为粒子增添一些大小和旋转的随机性。最终的效果就出来了。

理论上说,任何的动画效果都可以导出带 Alpha 通道的图像序列,然后通过精灵图集导入到 Cocos Creator 中。所以 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 精灵图集是如何组合的,在 NumTilesXNumTilesY 中分别输入精灵图集的行数和列数。由于不再需要动画效果,因此也不再需要给 FrameOverTime 曲线数值,让它保持默认的常数值 0 即可。StartFrame 控制动画起始帧,既然没有动画效果,粒子就会静止在 StartFrame 所定义的帧数。还记得我们使用最大值和最小值制作随机效果的技巧吗?同理可以为 StartFrame 设定最大帧值和最小帧值,让粒子系统在其中随机取帧(注意:最小的帧数是 1,不是 0)。最后,我们仍然需要为 CycleCount 输入数值,因为虽然没有动画,粒子系统仍然需要循环精灵图集中的所有序列以随机取帧。

雨点的随机取帧有了,但是雨点的贴图遭到了非常严重的拉伸。这是由于雨点贴图并不是一个正方形,粒子在 Billboard 的渲染模式下,会将贴图拉伸到 1:1 的长宽比。要解决这个问题,我们可以使用之前了解过的 StartSize 参数。

默认情况下,StartSize 模块对粒子大小的控制是等比的,我们可以勾选 StartSize3D,在 StartSizeXStartSizeYStartSizeZ 轴分别输入数值,将粒子缩放到符合雨点贴图的比例。

问题虽然解决了,Billboard 还有另外一个问题:Billboard 是永远正对摄像机的。但是我们不希望场景中落下的雨点永远正对摄像机:们低头观察时,雨点应当从我们的观察角度纵深掠过,而不会仍然是一条竖线。所以,Billboard 已经不适合用于雨点的粒子了,我们需要真正的 3D 模型作为雨点的粒子。

将 Renderer 标签下的 RenderMode 参数选择为 Mesh,这将会使每个粒子以 3D 模型的形式发出。随后,在下方的 Mesh 参数中选择使用的模型。我们可以把任何导入模型的网格文件拖拽到 Mesh 参数中。这里一个简单的面片就能达到目的,所以可以使用引擎内置的四边面模型 quad.mesh

虽然使用了 3D 模型作为粒子,但是生成的每个粒子依然面朝一个方向,我们还需要让每个粒子在出生时获得一个随机的旋转数值。StartRotation 参数我们之前已经使用过了,与 StartSize 类似,勾选 StartRotation3D,在 StartRotationXStartRotationYStartRotationZ 中分别输入数值,或使用最大值和最小值定义随机的范围。

回到雨点的粒子材质: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 模式非常适合火焰的制作。

粒子系统方面,选取锥形的发射器,将 AngleLength 参数都设为 0,使发射的粒子不会向外飞散,并且保证粒子都在同一水平面上射出。火焰粒子应该排列较为密集,大致以稍低于气体上升的速度上升,但火苗只能蹿升到一定的最高高度,说明粒子的生命周期比较短。所以 StartSpeed 可以取略小于 1 的数值,StartLifetime 也需要较小的数值。

火焰通常看上去整体呈钟形,这意味着粒子在刚发射时的尺寸比较大,随着生命周期逐渐变小。我们之前遇到的大多数粒子案例,都是发射时尺寸较小,随生命周期逐渐增大的“上坡”曲线。对于火焰,可以在 SizeOvertimeModule 模块中使用一个“下坡”曲线。

将材质赋予粒子系统,开启 TextureAnimationModule 模块,之前我们已经使用过了 CurveTwoConstants 两种数值类型。TwoCurves 相当于它们二者的结合:粒子会在同一个生命周期中的时间点在两条曲线的数值之间随机取值。我们可以将 FrameOverTime 参数设定为 TwoCurves 类型,并给予一条“上坡”曲线和一条“下坡”曲线,得到的结果就是有的粒子以正序播放精灵图集,有的以倒叙播放,有的取两者的中间值。我们之前还使用过 StartFrame 参数,它决定了精灵图集播放的起始帧,使用一个最大值和最小值,可以让粒子随机从图集中选择一帧开始播放。

与烟雾一样,可以使用 ColorOverLifetimeModule 模块,使用 Alpha 值将刚发出和即将消失的粒子隐藏,使火焰的整体形态更加平滑。使用渐变中的 RGB 数值,可以为火焰的某一个区间的颜色进行微调,丰富火焰的颜色和明度变化。

粒子的飞行轨迹、随机性和整体形态都有了,我们只需要和之前一样,调整粒子的频率和密度,增添一些旋转和大小的随机性,火焰的效果就实现了。

对于许多项目来说,火焰的制作到这里就可以结束了。然而,虽然我们的粒子看上去比较像火焰,但单独放在场景里还是难免有假的感觉。在这种情况下,我们不需要考虑增加渲染的复杂度,去追求更高的粒子数量,反之,可以打造一些在现实中会伴随粒子出现的细节,比如:火焰一定伴随着烟雾的产生,并且会有燃烧不完全的火星飞出;降雨在比较强烈时,会在地面附近形成一层较薄的水蒸气等。

烟雾我们已经制作完成了,火星的制作也并不复杂:火焰的精灵图集已经有了,只需要制作符合火星飞行规律的粒子即可。

我们将在此基础上修改来实现火星的效果。将火焰粒子系统复制一份,火星可以继续使用火焰的精灵图集,我们可以稍微调整 ColorOverLifetimeModule 的渐变颜色,让它更鲜明一些。

火星的最大特征在于:

  • 尺寸较小,StartSize 参数或 SizeOvertimeModule 模块的取值应该比较小,但仍然肉眼可见;

  • 飞行轨迹不同,火星是燃烧不完全的细小固体颗粒,不应该像火焰一样集聚在一起,相反,在热能的作用下应该有向外飞出的趋势。飞出后受其自身质量的影响,应该有下降的趋势。

我们在制作火焰时选择的锥形发射器,本身就是在以锥形方向发射粒子的,只需要把 Angle 参数恢复为一定的数值给锥形一定的角度即可。位于发射器属性最下方的 RandomDirectionAmountRandomPositionAmountSphericalDirectionAmount 参数我们之前介绍过,它们可以为粒子的发射增加位置和方向的随机变化。除此之外,现实中的火星有些可以弹射的很高,有些只能飞到较低高度,这个区别其实就是粒子飞行速度的区别,可以用 StartSpeed 参数轻松实现。最后,我们需要制作火星受重力影响下落的动能,在制作烟雾的过程中我们使用了 ForceOvertimeModule 模块为烟雾的漂浮提供了动能变化,在普通粒子的基本参数中有一个方便的 GravityModifier 参数,能为粒子赋予重力的属性。当它的数值等于 0.98 时,粒子与绝大多数现实中的物体一样,发出后会直接落向地面。因此我们只需要给火星一个非常小的 GravityModifier 数值,使他能够飞行的同时,保持受重力影响的动能。

火星制作完成之后,将火焰、火星和烟雾打成一组放置在场景里,当然也不要忘了放上一盏火红色的球形灯,将火焰周遭照亮。做完这些,火焰的可信度是否提升了不少呢?

喷火和烛火(粒子的变体)

我们已经完成了一个完整的火焰粒子系统,然而在项目中虽然火焰用的地方不少,但端端正正的一团篝火的使用机会还是比较有限的。如果我们需要制作火焰的其他形态:比如喷射的火焰、蜡烛的烛火呢?

喷火最终效果

喷射的火焰看上去很复杂,但与我们之前制作的粒子并无差别:首先是形态,我们对粒子的发射速度、密度、粒子的大小变化等要素的掌控已经非常熟悉了。这种喷涌而出的火焰如何制作,其实一定程度上我们已经解答了:在制作篝火时,我们基于制作烟雾的经验,给予 SizeOvertimeModule 一个“下坡”的曲线使粒子随生命周期变小,现在只需要反其道行之,给予 SizeOvertimeModule 一个“上坡”的曲线即可得到发射后不断膨胀的火焰粒子,这与对烟雾粒子的大小控制是一样的。火焰喷射的强劲动能可以理解为粒子发射的速度,StartSpeed 仍然是不二选择。

喷射产生的烟雾,在遵循着喷射的方向飞行一段距离之后,因为自身较轻的质量应该向上飘向空中。我们对粒子发射后飞行轨迹的控制已经很熟悉了,ForceOvertimeModule 将帮助我们实现其效果。在制作火星时我们介绍了 GravityModifier 参数,将 GravityModifier 设为负值也能得到反重力的效果,使粒子向空中飘去。除此之外,VelocityOvertimeModule 模块可以为粒子的发射提供一个具体数值和方向的加成,如果需要粒子飞行中能够一定程度上抵抗 ForceOvertimeModuleGravityModifier 的影响,则可以开启它。与之相对的,LimitVelocityOvertimeModule 模块能够提供一个反作用于 VelocityOvertimeModule 的加成,它会优先作用处于生命周期末尾的粒子。与 VelocityOvertimeModule 相结合使用,由此,我们可以做出粒子先受喷射的动能影响飞行,然后动能耗尽,粒子只受重力和 ForceOvertimeModule 影响的过渡变化。

至于火星,在喷射之后首先会遵循着喷射的方向飞行,但受到烟雾的影响,它落向地面的趋势不明显,反而会一部分被烟雾带到空中。使用上述的模块配合,我们同样可以指定火星的飞行受力和轨迹。

最后,ColorOverLifetimeModule 依然是粒子整体呈现的重要一环,我们可以将渐变的左侧,也就是粒子刚射出部分的颜色加以调整,使其呈现一种蓝绿色,模拟部分化学成分在极高温下火焰的颜色。不仅是颜色变化,火焰的 Alpha 值同样非常重要,火焰粒子材质使用 Add 模式,我们可以尝试在渐变中加入更多偏暗的颜色节点,在产生颜色变化的同时,让 Alpha 的融合更加自然。

烛火最终效果

相较于喷火的激烈,烛火则比较容易被人忽视。在一些项目中(其中不乏国外的经典之作)甚至直接把缩小版的篝火作为烛火使用。虽然理论上烛火和普通的篝火没有什么区别,然而从视觉的角度,烛火有它独有的特点:

  • 颜色较亮,只有尾部会呈现部分火红色,主体部分近乎于白色;

  • 整体形态比较统一,没有复杂的形态和细节变化,但仍然具有火焰的跳跃感;

我们仍然可以把缩小后的篝火作为起点。首先,既然烛火的形态比较统一,那么火焰的精灵图集就没有必要登场了,直接使用一个静态的圆形渐变,或者在材质 MainTexture 参数的下拉菜单中选择引擎自带的 Default-Particle 贴图。既然使用了圆形贴图,粒子旋转的变化也不再有必要了。与烛火相比,篝火的尾部有许多细小的火苗,我们之前一直使用 ColorOverLifetimeModule 将头部和尾部的粒子隐藏,同理,我们在使用 ColorOverLifetimeModule 时可以更激进一些,将隐藏的范围进一步扩大,直至篝火尾部的所有火苗都隐藏起来。这样一个浑然一体的烛火轮廓就产生了。最后,烛火的颜色变化同样可以通过 ColorOverLifetimeModule 实现,在制作喷火时已经使用了这种操作:将渐变的左侧设为蓝色,右侧设为火红色,分别为烛火的头部和尾部赋予颜色。一个带有颜色变化,清晰而干净的烛火就完成了。


今天我们通过 Cocos Creator 的粒子系统,实现了烟雾、星光、降雨、火焰、喷火和烛火的粒子效果呈现,并且将粒子系统中主要的功能模块和制作方法介绍了一遍。你会发现:自然界中的种种效果虽然看上去变化无常,实际上都有一定的规律可循,添加一定的随机变化,加以一定数量的粒子叠加,我们可以制作出各种令人信服的粒子效果特效。

往期精彩

超长干货!Cocos Creator 粒子系统详解,零代码实现逼真自然效果相关推荐

  1. 最简单太阳系H5动画canvas详解 零基础可入

    最简单太阳系H5动画canvas详解 零基础可入 最终结果:(实际为动画效果,金星绕轨道转动) 页面准备/html 要使用canvas,需要首先在页面中要绘制的位置放入canvas标签元素,在后期的绘 ...

  2. 什么是移动端开发【重点学习系列---干货十足--一万字详解】

    引言 这一篇文章主要对移动端开发相关的基础知识点,进行总结.从移动端开发的一些概念.专有名词.缩放.viewport移动端事件.适配问题以及一些工作中沟通经常会用到这些方面来说一下移动端 文章目录 引 ...

  3. OpenGL粒子系统详解及编程实现

    OpenGL粒子系统详解及编程实现 标签: opengl编程 2016-08-23 14:23  1114人阅读  评论(0)  收藏  举报   分类: OSG(6)  版权声明:本文为博主原创文章 ...

  4. 图像质量损失函数SSIM Loss的原理详解和代码具体实现

    本文转自微信公众号SIGAI 文章PDF见: http://www.tensorinfinity.com/paper_164.html http://www.360doc.com/content/19 ...

  5. 一文速学数模-时序预测模型(四)二次指数平滑法和三次指数平滑法详解+Python代码实现

    目录 前言 二次指数平滑法(Holt's linear trend method) 1.定义 2.公式 二次指数平滑值: 二次指数平滑数学模型: 3.案例实现 三次指数平滑法(Holt-Winters ...

  6. 算法 经典的八大排序算法详解和代码实现

    算法 经典的八大排序算法详解和代码实现 排序算法的介绍 排序的分类 算法的时间复杂度 时间频度 示例 图表理解时间复杂度的特点 时间复杂度 常见的时间复杂度 空间复杂度 排序算法的时间复杂度 冒泡排序 ...

  7. 扫描线填充多边形算法详解与代码

    扫描线填充多边形算法详解与代码 首先给出已知信息:多边形结构体里面包含三个信息:顶点个数,顶点和颜色 class MyPolygon {public:int m_VerticeNumber;CPoin ...

  8. 调包侠福音!机器学习经典算法开源教程(附参数详解及代码实现)

    Datawhale 作者:赵楠.杨开漠.谢文昕.张雨 寄语:本文针对5大机器学习经典算法,梳理了其模型.策略和求解等方面的内容,同时给出了其对应sklearn的参数详解和代码实现,帮助学习者入门和巩固 ...

  9. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

最新文章

  1. 《Effective Java》读书笔记--创建和销毁对象
  2. 【android】java.lang.NoClassDefFoundError或classnotfount等异常错误
  3. Excel问题汇总!
  4. javaScript的使用(5)DOM事件
  5. 【cropper】介绍:JavaScript图片裁切
  6. VS2010 RTM
  7. 大数据学习笔记01:大数据概述
  8. stata基本操作(二)
  9. Java Hex 16进制的 byte String 转换类
  10. 轻松一刻,python乌龟绘图-小猪佩奇,可爱乌龟,新冠病毒
  11. 纯净版Windows7系统迅雷下载路径
  12. 旋转Kubernetes中的秘密
  13. 【问题记录】Win10笔记本电脑禁用自带键盘的方法
  14. nginx中配置不输入端口(指定地址)访问项目的方法
  15. 【3Dsmax】入门
  16. Access denied for user ‘root‘@‘localhost‘
  17. 问题 E: 1.10 旅行时间  根据火车的出发时间和到达时间,编写程序计算整个旅途所用的时间。
  18. 科学释梦——意识窗口在记忆模块间的穿越
  19. java B2B2C Springcloud电子商务平台源码
  20. 利用Excel进行相关、回归分析

热门文章

  1. 【数据结构与算法篇】什么是后缀表达式?
  2. php 数组下标初始化,php中如何初始化一个数组 | 学步园
  3. 新加坡计算机金融专业,新加坡金融专业为何如此热门?
  4. 数据模型篇:二、阿里巴巴数据整合及管理体系
  5. android+busybox+编译,busybox安装详解
  6. 找不到libgvplugin_pango.so.6的问题
  7. 【颇尔】Stax mAx深层过滤平台
  8. HTML做一个简单漂亮的宠图书馆 1页纯html代码实训素材
  9. apqp过程流程图及编写规则_APQP开发流程.
  10. 关于录音器材,你想要知道的都在这里