Unity粒子系统Sub Emitters实战:三阶段电影级烟花特效制作
1. 项目概述从零到一构建三阶段烟花特效在游戏和交互式视觉项目中烟花特效几乎是营造节日氛围、庆祝场景或华丽技能释放的标配。很多开发者初次接触Unity粒子系统时可能会用单个粒子发射器模拟烟花但效果往往生硬、缺乏层次感——升空轨迹单一爆炸瞬间突兀消散后一片空白。这正是我们今天要解决的痛点如何制作一个拥有完整生命周期的、电影级质感的烟花效果答案就是深度利用粒子系统的Sub Emitters子发射器模块。简单来说Sub Emitters允许你在一个粒子的生命周期中的特定时刻如诞生、碰撞、死亡时在其当前位置“孵化”出全新的、完全独立的粒子系统。这就像给粒子赋予了“繁衍”的能力。一个主粒子比如升空的“礼花弹”在死亡时可以触发一个子发射器生成爆炸的“星火”而这些“星火”粒子在死亡时又可以再次触发另一个子发射器生成缓缓下落的“余晖”粒子。通过这种链式反应我们就能轻松实现“升空 - 爆炸 - 余晖”这三个紧密衔接又各具特色的视觉阶段。这个项目不仅是一个特效制作教程更是一次对粒子系统模块化、事件驱动思维的实战训练。你将掌握如何拆分复杂视觉效果为多个简单系统并通过精确的事件绑定将它们串联起来。文末附带了完整的Unity项目文件包含了所有参数配置好的预制体你可以直接导入学习或作为基础模板进行二次创作。无论你是想为你的独立游戏增添一抹亮色还是为你的交互艺术项目寻找灵感这套方法都能为你提供扎实的技术支撑。2. 核心思路与模块化设计制作一个逼真的烟花不能只靠一个粒子发射器狂喷粒子。我们需要像导演分镜一样将整个过程分解为独立的、可精细控制的环节。Sub Emitters模块正是实现这种“分镜”的绝佳工具。我们的核心设计思路是一个主发射器负责模拟礼花弹的升空轨迹在其生命终结Death时触发第一个子发射器模拟爆炸瞬间的强光和扩散的星火随后每个扩散的星火粒子在生命终结时再触发第二个子发射器模拟星火燃烧殆尽后缓缓飘落的灰烬或余晖。这种设计有三大优势。第一是逻辑清晰每个阶段升空、爆炸、余晖都是一个独立的粒子系统GameObject我们可以单独调整其发射形状、速度、生命周期、颜色渐变等所有参数互不干扰。第二是性能可控通过精确控制每个子发射器的触发概率和发射数量我们可以避免在屏幕上同时存在海量粒子尤其是在移动端这种链式触发比用一个系统持续发射大量粒子要高效得多。第三是效果逼真它模拟了真实烟花的物理过程一个实体礼花弹升空内部火药爆炸产生多个发光体星火发光体燃烧后产生残留物余晖下落。在动手之前我们需要在脑海中规划好这三个系统的“父子关系”和“触发关系”。主系统Particle System Root是根节点它包含升空粒子系统。在其Sub Emitters模块中我们将“Death”事件链接到爆炸粒子系统Explosion。接着在爆炸粒子系统的Sub Emitters模块中我们再将“Death”事件链接到余晖粒子系统Afterglow。这样就形成了一条单向的事件链。这里有一个关键细节子发射器系统本身也是一个完整的粒子系统组件它可以被多个父系统引用也可以拥有自己的子发射器从而实现无限层级的复杂效果比如余晖粒子再触发更微小的火花。但为了性能和清晰度我们本次只做三层。3. 第一阶段升空礼花弹的打造升空阶段是烟花的起点它决定了烟花的发射高度、轨迹和节奏感。我们的目标是创建一个快速、笔直或略带弧线上升的“光球”。首先在Unity场景中创建一个空GameObject命名为“Firework_Root”。为其添加一个Particle System组件这个就是我们的主发射器重命名为“Launch”。在Inspector面板中我们先进行基础重置点击Particle System组件右上角的三个点选择“Reset Module”确保从一个干净的状态开始。发射模块Emission我们不需要持续发射烟花是一颗一颗放的。因此将“Rate over Time”设为0然后在“Bursts”列表中添加一个爆发Burst。设置Time为0.0表示游戏一开始就发射Count为1表示只发射一颗粒子。如果你希望模拟连发可以在这里添加多个Burst点。形状模块Shape这决定了粒子出生的位置和初始方向。选择“Sphere”球体形状并将Radius半径设为一个很小的值比如0.05。这会让粒子从一个近乎点状的位置发射模拟从炮筒中射出的感觉。将“Shape”的Rotation适当调整可以改变发射方向例如让X轴旋转90度使其向斜上方发射。基础属性模块Main这是核心参数区。持续时间Duration设为1.5秒。这是整个主粒子系统的运行时间但因为我们只爆发一颗粒子它主要影响后续循环。起始生命周期Start Lifetime设为2秒。这意味着这颗“礼花弹”粒子会存在2秒后消亡触发子发射器爆炸。这个时间就是升空飞行的时间。起始速度Start Speed设为8到10。给粒子一个向上的初速度。起始大小Start Size设为0.2到0.3模拟一个小光球。起始颜色Start Color选择一个明亮的颜色比如橙黄色RGB: 255, 200, 50。可以给一点随机性Random Between Two Colors让每次发射的色调略有不同。重力修改器Gravity Modifier设为0.5到0.8。这是一个关键参数如果设为0粒子会匀速直线飞行很不自然。给予一个正的重力值粒子在上升过程中会因“重力”而减速在生命末期速度降为0甚至开始下坠形成真实的抛物线轨迹。这正是模拟礼花弹动能耗尽的过程。速度随生命周期变化模块Velocity over Lifetime为了进一步控制轨迹我们可以在这里添加一个向下的速度例如Y轴为-2。这可以与重力配合创造出更复杂的运动曲线比如先快后慢或者在最高点有短暂的悬停感。渲染器模块Renderer选择合适的材质。Unity默认使用“Particle Standard Unlit”材质和“Default-Particle”纹理这是一个简单的 additive 着色器发光效果很好。你也可以使用一个自制的圆形渐变纹理让光球看起来更柔和。确保“Render Mode”为“Billboard”广告牌让粒子始终面向相机。实操心得升空粒子的“生命末期速度”至关重要。理想的效果是粒子在生命周期Start Lifetime结束的那一刻速度恰好减到接近零到达抛物线的最高点。这样爆炸子发射器被触发时烟花就在视觉上的最高点绽放非常自然。你需要反复微调 Start Speed、Gravity Modifier 和 Velocity over Lifetime甚至配合使用“Limit Velocity over Lifetime”模块来阻尼速度以达到这个效果。一个技巧是在Scene视图中播放选中粒子观察其运动轨迹线Gizmo确保轨迹线顶端平滑趋近于水平。4. 第二阶段爆炸瞬间的星火绽放这是烟花最华丽的部分。我们需要在升空粒子死亡的位置瞬间爆发出大量向四周飞溅的、发光的小粒子。在“Firework_Root”下创建一个新的子GameObject命名为“Explosion”。为其添加Particle System组件。这个系统将作为子发射器被触发因此其Looping循环选项必须取消勾选我们只希望它在被触发时播放一次。回到主“Launch”粒子系统展开最下方的“Sub Emitters”模块。点击模块左侧的复选框启用它。你会看到列表默认有“Birth”诞生和“Death”死亡等事件。点击“Death”事件右侧的圆形对象选择按钮将场景中的“Explosion”粒子系统拖入。这意味着当“Launch”粒子死亡时会在其位置触发“Explosion”系统。现在配置“Explosion”系统本身Main模块Duration设为0.5秒一次短暂的爆炸Start Lifetime设为0.8-1.2秒星火存留时间Start Speed设为5-8爆炸的初速度Start Size设为0.05-0.1细小的星火。Start Color可以设置为随机介于两种亮色之间例如黄色和红色营造热烈的感觉。Emission模块将Rate over Time设为0在Bursts中添加一个BurstTime为0.0Count设置为30到50。这表示在爆炸瞬间被触发的那一刻一次性发射出30-50个星火粒子。Shape模块选择“Sphere”或“Hemisphere”半球体。如果选择Sphere将Radius设为0这样所有粒子从中心点爆发。如果选择Hemisphere并调整方向可以模拟向特定方向扩散的爆炸。更高级的玩法是使用“Circle”形状并调整Arc弧度创造扇形爆炸。Velocity over Lifetime模块在这里我们可以给Y轴一个负值例如-3模拟星火在爆炸后受到重力下坠。同时可以给速度加一些随机性Randomize让运动更自然。Color over Lifetime模块这是让爆炸“活”起来的关键。点击颜色条打开渐变编辑器。通常设置为起始为白色极高亮度在很短的时间内前10%的生命周期快速过渡到Start Color如红色/黄色然后在后续生命周期中逐渐变暗、透明。这模拟了星火瞬间高温发光然后冷却的过程。Size over Lifetime模块同样关键。星火不应该大小不变。可以设置为粒子诞生时大小正常在生命中期略微变大模拟膨胀然后在生命末期快速缩小至消失。使用曲线编辑器可以精细控制这个过程。注意事项子发射器“Explosion”的坐标空间是一个容易忽略的点。在Sub Emitters模块中每个链接的子发射器都有一个“Inherit”属性下拉菜单。默认是“None”即子发射器使用自己的本地坐标系。如果选择“Inherit”子发射器会继承父粒子的某些属性如速度、颜色、大小。对于爆炸效果我们通常选择“Inherit”中的“Velocity”继承速度并设置一个比例如0.5。这样爆炸的星火会额外获得父粒子升空弹死亡时的剩余速度使得爆炸效果在视觉上具有惯性更加真实。如果升空弹是斜向上飞的继承速度后爆炸整体也会有一个斜向上的运动趋势而不是完全从静止点爆发。5. 第三阶段唯美余晖的模拟爆炸的星火绚丽但短暂而缓缓飘落的余烬或光尘能为烟花增添一份悠长、浪漫的韵味。我们将让每一个“Explosion”星火粒子在死亡时触发最终的“Afterglow”效果。在“Explosion”物体下再创建一个子GameObject命名为“Afterglow”。为其添加Particle System组件同样取消Looping。然后选中“Explosion”粒子系统启用其“Sub Emitters”模块在“Death”事件中链接上刚刚创建的“Afterglow”系统。现在配置“Afterglow”系统它的风格应与激烈的爆炸截然不同Main模块Start Lifetime设为2-3秒缓慢飘落Start Speed设为一个很小的值比如0.5甚至为0。因为我们希望余晖几乎是静止开始下落的。Start Size可以比星火更小如0.02-0.05。Start Color选择暗红色、橙色或灰白色亮度要低很多。Emission模块Rate over Time为0。在Bursts中添加Time为0.0但Count设为1。这意味着每一个“Explosion”星火粒子死亡时只产生一个“Afterglow”粒子。这符合物理直觉一个火星熄灭产生一缕轻烟。Shape模块选择“Sphere”Radius设为0.01或0确保余晖粒子在父粒子位置精确生成。Velocity over Lifetime模块主要给Y轴一个恒定的负值如-0.5模拟重力下落。同时可以在X和Z轴添加非常微小的随机速度或使用噪声模拟空气扰动的飘忽感。Color over Lifetime模块渐变设置为从半透明的暗色开始在整个生命周期中逐渐变得完全透明。可以保留非常微弱的颜色。Size over Lifetime模块粒子可以缓慢地缩小或者先略微维持大小再缩小。Noise模块强烈推荐启用这是让余晖“活”过来的灵魂。启用Noise模块调整Strength强度为一个较小的值如0.1Frequency频率可以高一些如0.5。这会给余晖粒子的运动路径添加非常自然的、平滑的随机扰动模拟轻烟在空气中受到微小气流影响而蜿蜒飘散的效果彻底告别机械的直线下落。避坑技巧到这里你可能播放测试发现屏幕上的粒子数量爆炸尤其是爆炸星火数量多时导致性能下降。这里有几个控制技巧1.利用Emit Probability发射概率在“Explosion”系统的Sub Emitters模块中链接了“Afterglow”的那一行有一个“Emit Probability”属性。默认是1即100%触发。你可以将其降低到0.3或0.5这样只有一部分星火会产生余晖既能保持效果又大幅减少粒子数量。2.限制总粒子数在每个粒子系统的Main模块底部都有“Max Particles”选项。为“Afterglow”系统设置一个合理的上限如50防止极端情况下粒子无限累积。3.精细调整生命周期和数量平衡“Explosion”的Burst Count、“Explosion”粒子的Lifetime和“Afterglow”的Lifetime。让它们错开峰值避免所有粒子同时出现同时消失。6. 高级调优与视觉增强基础的三阶段链条搭建完成后你的烟花已经能看了但距离“惊艳”还差一些灵魂性的细节。下面这些高级调优技巧能让你的特效质感提升一个档次。6.1 光照与阴影的考量默认的粒子材质如Particle Standard Unlit是不受场景灯光影响的它们自己就是光源。这对于明亮的烟花核心是合适的。但如果你希望余晖粒子能与场景互动可以考虑使用“Particle Standard Surface”或自定义Shader的材质并为其赋予一个能接收简单光照的Shader。更实用的技巧是使用粒子系统自带的灯光模块Lights Module。启用后你可以让每个粒子特别是爆炸星火在生成时在其位置创建一个短暂的点光源。这能动态照亮周围的场景物体比如地面、建筑瞬间增强烟花的空间感和氛围。注意要谨慎使用因为实时灯光非常耗费性能通常只对少数几个核心粒子启用并且设置很短的Range和很短的Lifetime。6.2 使用Trails模块为升空轨迹添加拖尾一个光秃秃的光球上升有点单调。选中“Launch”粒子系统启用“Trails”模块。这个模块可以让粒子在运动轨迹上留下拖尾。将“Lifetime”设置为一个比粒子本身生命周期稍短的值如0.3“Width over Trail”可以设置为由粗到细。在“Color over Trail”中可以设置拖尾从粒子颜色渐变到透明。这样升空的礼花弹就会拖着一条绚丽的尾迹视觉效果立刻丰富起来。一个关键参数是“Inherit Particle Color”通常要勾选让拖尾颜色继承粒子的颜色变化。6.3 为爆炸添加二次爆炸或闪光效果大型烟花往往是多重爆炸的。我们可以利用Sub Emitters的“Birth”事件来模拟。在“Explosion”粒子系统的Sub Emitters模块中除了“Death”链接到“Afterglow”我们还可以在“Birth”事件链接另一个粒子系统比如叫“Flash”。这个“Flash”系统配置为发射少量如3-5个生命周期极短0.1秒、大小快速膨胀然后消失的白色粒子。材质使用Additive亮度极高。这样在爆炸发生的一瞬间会先有一个强烈的闪光然后再扩散出彩色星火模拟火药瞬间爆燃的冲击波效果让爆炸更有力量感。6.4 音频的同步集成视觉有了声音不能缺席。Unity的粒子系统本身不直接播放音频但我们可以通过脚本或更优雅的方式——使用Audio Source组件与粒子事件结合。在“Firework_Root”上添加一个Audio Source组件拖入爆炸音效。然后我们需要一个脚本监听粒子系统的事件。Unity提供了OnParticleSystemStopped回调但这里更精准的是使用粒子系统的Trigger模块配合脚本。一个更简单直接的方法是为“Explosion”粒子系统添加一个“Particle System”组件的事件接收器这需要一点点代码。或者你可以写一个简单的脚本挂在“Explosion”物体上using UnityEngine; public class PlaySoundOnParticlePlay : MonoBehaviour { private ParticleSystem ps; public AudioClip explosionSound; private AudioSource audioSource; void Start() { ps GetComponentParticleSystem(); audioSource GetComponentAudioSource(); if (audioSource null) { audioSource gameObject.AddComponentAudioSource(); } audioSource.playOnAwake false; audioSource.clip explosionSound; } void Update() { // 简单检测如果粒子系统开始播放且之前未在播放则播放音效 if (ps.isPlaying !audioSource.isPlaying) { audioSource.Play(); } } }将这个脚本挂到“Explosion”物体上并为其Audio Source组件或脚本public变量指定爆炸音效。这样每当爆炸粒子系统被触发播放时就会同时播放音效。7. 性能优化与批量管理实战当你在一个场景中需要同时播放数十个甚至上百个这样的烟花时性能问题就会凸显。粒子系统是性能杀手尤其是Draw Call绘制调用和Overdraw过度绘制。以下是一线项目中总结的优化策略。7.1 粒子数量与预算控制这是最直接的优化。为每个阶段的粒子系统设置严格的“Max Particles”上限。例如“Launch”系统最多同时存在5个模拟连发“Explosion”系统上限设为100“Afterglow”系统上限设为150。在Particle System组件的Main模块最下方直接设置。同时回顾之前提到的“Emit Probability”降低非必要粒子的触发概率。7.2 使用GPU Instancing与合批在粒子系统的Renderer模块中检查是否勾选了“Enable GPU Instancing”。对于使用相同材质的粒子GPU Instancing可以极大地减少Draw Call。确保你的粒子材质Shader支持GPU Instancing。此外尽量让所有烟花使用同一套材质即使颜色通过脚本或粒子属性动态改变这样Unity更容易进行动态合批。7.3 层级管理与对象池技术频繁地实例化Instantiate和销毁Destroy包含粒子系统的GameObject是性能大忌。正确的做法是使用对象池Object Pooling。你可以预先创建好多个“Firework_Root”预制体的实例并设置为非激活状态。当需要播放一个烟花时从池中取出一个激活它播放完毕后不是销毁它而是将其所有粒子系统停止并重置然后放回池中等待下次使用。这样可以避免内存分配和垃圾回收GC带来的卡顿。一个简化的对象池使用示例如下需自行完善using System.Collections.Generic; using UnityEngine; public class FireworkPool : MonoBehaviour { public GameObject fireworkPrefab; public int poolSize 20; private QueueGameObject pool new QueueGameObject(); void Start() { for (int i 0; i poolSize; i) { GameObject obj Instantiate(fireworkPrefab); obj.SetActive(false); pool.Enqueue(obj); } } public GameObject GetFirework() { if (pool.Count 0) { GameObject obj pool.Dequeue(); obj.SetActive(true); // 重置所有粒子系统 ParticleSystem[] psArray obj.GetComponentsInChildrenParticleSystem(); foreach (var ps in psArray) { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); ps.Play(); } return obj; } return null; } public void ReturnFirework(GameObject obj) { obj.SetActive(false); pool.Enqueue(obj); } }7.4 LOD多层次细节策略对于远处的小烟花你完全不需要渲染那么精细的余晖甚至可以将爆炸的粒子数量减半。可以通过判断烟花与摄像机的距离动态切换不同细节等级的烟花预制体或者通过脚本动态调整粒子系统的“Emission Rate”和“Max Particles”。Unity的LOD Group组件通常用于Mesh对于粒子系统需要自己写逻辑控制。8. 完整项目文件解析与使用指南为了方便大家学习和直接应用我准备了一个完整的Unity项目文件包。这个项目基于Unity 2021.3 LTS版本创建但核心粒子系统功能在2018.3及以上版本都是兼容的。项目结构如下Assets/Firework_Example/Prefabs/包含了制作好的烟花预制体。Firework_Basic.prefab基础三阶段烟花参数均衡适合大多数场景。Firework_WithTrail.prefab带有拖尾效果的升空烟花。Firework_MultiColor.prefab爆炸时会产生多种随机颜色的星火。Firework_Launcher.prefab一个简单的发射器附带了脚本可以按空格键连续发射烟花非常适合测试和表演。Scripts/包含两个实用脚本。SimpleFireworkLauncher.cs绑定在发射器上控制发射间隔和位置随机。ParticleSystemAutoReturnToPool.cs一个简单的脚本挂在烟花预制体上当所有粒子播放完毕后自动通知对象池回收自己需要配合对象池管理器使用。Materials/使用了几个简单的Particle Unlit材质配合不同的纹理圆形、软边缘、星星形。Scenes/Demo.unity一个展示场景包含了地面、天空盒和几个预设的发射点。导入与使用步骤在Unity中新建一个项目或打开现有项目。将下载的.unitypackage文件拖入Unity编辑器窗口按照提示导入所有资源。打开Assets/Firework_Example/Scenes/Demo.unity场景。点击播放你将会看到预设的烟花表演。按下空格键可以从摄像机位置随机发射烟花。要查看或修改某个烟花在Prefabs文件夹中找到对应的预制体拖入场景或直接双击打开进行编辑。所有粒子系统的参数都已展开你可以直接调整数值并实时看到效果变化。自定义你的烟花这个项目文件最大的价值在于它是一个“参数化”的模板。你可以通过调整我上面章节提到的各个模块的参数轻松创造出属于你自己的烟花变体。例如改变颜色在“Explosion”系统的“Start Color”中选择“Random Between Two Gradients”两个渐变之间随机可以设置五彩斑斓的爆炸。改变形状将“Explosion”的“Shape”从“Sphere”改为“Circle”并调整“Arc”为180度可以创造出扇形绽放的烟花。改变节奏调整“Launch”粒子的“Start Lifetime”和“Gravity”可以改变升空高度和爆炸时机。调整“Explosion”粒子的“Start Speed”和“Velocity over Lifetime”可以改变星火是剧烈扩散还是缓慢飘散。通过这个完整的项目你不仅能复现文章中的所有效果更能拥有一个可以随意实验和魔改的沙盒这才是掌握粒子系统艺术的最佳途径。

相关新闻