本文使用 UE4.26 版本,利用 ActionRPG 示例项目,对 UE 中的粒子特效 (Particle System) 进行学习,总结(虽然 UE5 已经不太打算用这个了,而是使用 Niagara,但是了解还是很有必要的),主要包括:
- 特效编辑器 Cascade 与 Particle System
- 特效相关优化
- 特效相关问题记录
一、Cascade 与 Particle System
1.1 Cascade 里的操作
-
Restart Level
空格(Space),可以按上边的 Restart Level 按钮一样,重新从 0 开始播这整个特效
-
切换发射器设置和整个特效设置
点击一个发射器(Emitter),Details 中会显示发射器的设置,点击发射器中的 Module,Details 中会显示 Module 的设置;如果想切换成整个特效的设置,点击最右侧的黑色区域即可(这也就是为什么不管怎么加发射器,最右边都会留有黑色区域)。 -
折叠发射器
双击发射器可以折叠发射器,虽然感觉没啥用。。
-
重置摄像机
在预览窗口鼠标右键、左键按住,WASD移动摄像机的操作和正常的编辑器游戏窗口中一样,但是有时候转着转着特效就不知道去哪儿了,这时候,点一下F
按键即可。 -
背景颜色和 Bounds
上方的Background Color
选项可以修改预览窗口的背景颜色,为了更好的观察特效;Bounds 按钮可以显示特效的 Bounds,用于查看是否会有问题,或者 Bounds 过大导致效率降低等。
1.2 Cascade 里的术语
在 UE 中编辑 ParticleSystem 的编辑器叫 Cascade(双击打开一个 Particle System 资源即可),界面如下图所示:
右侧中间的这部分最重要,是 Emitters,即粒子发射器。
其中每一个竖着的方块每一个 Emitter,Emitter 有四种类型(像下图就是一个 Mesh 类型 Emitter):
- Sprite 默认
- Mesh(网格,可以做成球形或者其他形状)
- Beam(激光类型)
- Ribbon(条带,如飞机拖尾烟雾)
每一个 Emitter 分为两部分:
其中:
- 发射器列 —— 每一列表示一个单独的发射器。
- 发射器块 —— 这是每个发射器顶部的一个框,其中包含发射器本身的主要属性和控件,例如发射器类型和发射器名称,还包含一些其他主要属性。
- 模块列表 —— 发射器块下方是定义发射器的外观和行为的所有模块的列表。所有发射器都有一个 必需 模块(Required Module),之后可以添加任意数量的模块来进一步定义行为。
每一个 Emitter 里的每一横条,是一个 Module(如下图就是一个 Required Module):
每个 Module 里的 Details 里,是对于这个 Module 或者说,这个粒子特效的描述(如下图就是 Required Module 的一部分 Detail)
1.3 一些 Note
想到再写
1.4 代码里的变量
在代码里,创建出的是 UParticleSystemComponent 类型的特效,如:
UParticleSystemComponent* PSC = UGameplayStatics::SpawnEmitterAtLocation(
Target->GetWorld(),
PSTemplate,
StartLocation,
Rotator);
其中所有的粒子是 Emitter Instances,即 1.1 中的 Emitters:
TArray<FParticleEmitterInstance*>& EmitterInstances = PSC->EmitterInstances;
这是个数组,其中每一个就是 1.1 中的每一个 Emitter(FParticleEmitterInstance 类型):
for (FParticleEmitterInstance* const EmitterInstance : EmitterInstances)
{
}
每个 Emitter 可以转成对应的类型,如 Beam 类型的可以直接转
FParticleBeam2EmitterInstance* const Beam = StaticCast<FParticleBeam2EmitterInstance*>(EmitterInstance);
if (Beam && Beam->BeamTypeData)
{
Beam->BeamTypeData->Speed = TraceSpeed;
}
对于 Emitter 中的每一个 Module,通过如下方式获取:
EmitterInstance ->CurrentLODLevel->Modules
想要获取特定类型的 Module,可以直接转,如 Lifetime 这个 Module,就是 UParticleModuleLifetime 类型的(详见 \UnrealEngine\Engine\Source\Runtime\Engine\Classes\Particles 下的文件夹和 .h)
其中 RequiredModule 比较特殊,单独存的(详见 UParticleLODLevel 类声明),即 每个发射器都有一个Required模块(官方翻译就是:默认必需的模块):
class UParticleLODLevel : public UObject
{
GENERATED_UCLASS_BODY()
/** The required module for this LOD level */
UPROPERTY(instanced)
class UParticleModuleRequired* RequiredModule;
/** An array of particle modules that contain the adjusted data for the LOD level */
UPROPERTY(instanced)
TArray<class UParticleModule*> Modules;
}
如 想拿到 RequiredModule 中的 EmitterLoops,即循环次数,可以直接:
EmitterInstance ->CurrentLODLevel->RequiredModule->EmitterLoops
1.5 Particle System 和 Particle System Component
Particle System(PS) 是特效资源,在 Content 目录下鼠标悬停在资源上,就能看到介绍;
Particle System Component(PSC) 是实际播放特效的组件,在世界中创建出来的是这个,可以挂在人身上,也可以不挂。Cascade 中的预览窗口,也是创建了一个 PSC,不过还继承了一层。
/** Components used for drawing the particle system in the preview viewport */
UCascadeParticleSystemComponent* ParticleSystemComponent;
二、Particle System 优化相关
2.1 优化相关概念
2.1 生命周期
- 粒子发射器 - 生命周期
每一个 Emitter 的生命周期,在Required Module
中的Duration
里设置:
其中:
Emitter Duration Use Range
、Emitter Duration Low
、Emitter Duration Low
- 用来将每次 Duration 设为一个范围的,一般不怎么用感觉;Emitter Loops
- 指这个发射器,循环多少次;0
表示无限循环,值得注意的是:这个值默认就是 0,而有一个发射器是无限循环的,那这个特效将会一直不销毁Emitter Duration
- 每一次发射的时长
- 粒子 - 生命周期
对于每个粒子,在LifeTime
Module 中可以设置,大部分粒子也不应该太长时间:
在Spawn Module
中,可以设置粒子发射的速率,如果 0
(默认值),代表发射器每次虚幻,粒子就发射一次,如果是 1
,则表示发射器每次循环过程中,粒子每秒发射一次。
2.1.2 粒子数量
每个 Emitter 面板上有一个数字,代表这个粒子发射器,一次发射多少粒子。在 Viewport 里右下角也可以看到。
在 Viewport 中,左上角点 View
可以选更多展示的信息。
2.1.3 LOD
Cascade 中,右上方这些是 LOD 相关设置,其中:
- 左右两边的
Add LOD
- 对应Add LOD Before
和Add LOD After
,即在当前 LOD 和下个最高(最低)的 LOD 之间插入一个 LOD Lower LOD
和Higher LOD
- 对应调到上一个或者下一个 LODLOD
- 就是当前 LOD 等级
选择一个 Emitter 后 Details 中显示的就是这个发射器的细节信息,如果想看整个特效的信息(比如 LOD),点一下右边的黑色空白区域即可。
可以在 Details 中看到 LOD 的设置:
这个地方,LODDistances
是不能添加的,需要用上边的 Add LOD
的按钮添加,这里自动就会添加了。
使用方法很简单,看注释就能看懂:
/**
* The array of distances for each LOD level in the system.
* Used when LODMethod is set to PARTICLESYSTEMLODMETHOD_Automatic.
*
* Example: System with 3 LOD levels
* LODDistances(0) = 0.0
* LODDistances(1) = 2500.0
* LODDistances(2) = 5000.0
*
* In this case, when the system is [ 0.0 .. 2499.9] from the camera, LOD level 0 will be used.
* [2500.0 .. 4999.9] from the camera, LOD level 1 will be used.
* [5000.0 .. INFINITY] from the camera, LOD level 2 will be used.
*
*/
UPROPERTY(EditAnywhere, editfixedsize, Category=LOD)
TArray<float> LODDistances;
越远的 LOD 特效应该越少,否则 LOD 就没有啥意义了,且不同 LOD 之间的设置不应该不一样,比如 SpawnRate
这种队表现影响非常大的参数。
根据官方 - Particle System Level of Detail (LOD) 的介绍,制作一个特效的 LOD 的步骤应该如下:
- 制作你觉得这个特效最全面的效果(就是全特效),这就是这个特效的 LOD 的最高层(LOD0) -
Create your overall desired effect. This will be the highest LOD level.
- 然后制作最低层 -
Next, create the lowest LOD level.
- 在中间添加任意层,是最高和最低之间可以平滑过渡 -
Add any other LOD levels between the two in order to create a smooth transition from highest quality to lowest.
注意:所有 Modules 都只能在最高层进行增加和删除操作。虽然可以这么做
在制作好最高层 LOD,特效人员觉得可以进行 LOD 的开发后,可以点击 Toolbar 中的 Regenerate Lowest LOD
或者 Regenerate Lowest LOD Duplicating Highest Button
按钮,区别在于,左边的按钮 是通过完全复制最高层,来生成一个最低层 LOD;而右边这个按钮 是生成一个最底层,并降低 Spawn Rate(亲测 Spawn Rate 会从 2 变成 0.2,降得还是挺多的)。
注意: 这个操作会删除现有的所有 LOD,除了最高等级的 LOD(会弹出一个确认框)。
降 SpawnRate 的代码如下,即默认是降到 10%,除了选完全复制最高层,以及目前不支持的 Beam 类型外。
bool UParticleEmitter::AutogenerateLowestLODLevel(bool bDuplicateHighest)
{
// blabla
float Percentage = 10.0f;
if (SourceLODLevel->TypeDataModule)
{
UParticleModuleTypeDataBeam2* Beam2TD = Cast<UParticleModuleTypeDataBeam2>(SourceLODLevel->TypeDataModule);
if (Beam2TD)
{
// For now, don't support LOD on beams and trails
Percentage = 100.0f;
}
}
if (bDuplicateHighest == true)
{
Percentage = 100.0f;
}
if (LODLevel->GenerateFromLODLevel(SourceLODLevel, Percentage) == false)
{
}
}
注意:LOD 默认距离是 2500(即 25 米),详见 void FCascade::RegenerateLowestLOD(bool bDupeHighest)
通过 Higher LOD 按钮(这里的 higher 指上边,其实是更低层级的 LOD),可以切到刚生成的最低级LOD,默认所有 Module 是 不能编辑 的(背景会有黑色花纹):
如果想编辑,在想编辑的 Module 上,右键然后选择 Duplicate from Highest
即可:
)
注意:: 对于 Emitter 来说,Detail 的信息(比如 Siginificance Level,Render Mode 等),只有在 LOD 0 是可以编辑的,其他层上都不能编辑,只能编辑 Module。
2.2 Cascade 中的优化
2.2.1 生命周期
美术人员在制作特效后,需要确认不是循环的特效,这个 Emitter Loop
值不是 0,否则对效率和内存都有影响。
在 Cascade 的预览窗口(Viewport)中,点 Restart Level
然后看什么时候会出现 Complete
字样(Complete 代表这个特效要销毁了),可以大致知道这个特效会持续多久,如果很久没有出现,那就需要注意了,是不是 Emitter Duration
配的很长。
2.2.2 性能
在 Viewport 窗口中,点 View
选择 View Modes -> Shader Complexity
,可以看到这个特效的复杂度,越红,复杂度越高。
运行时可以按 F5
切换成这个模式,白色说明性能已经非常差了!!
2.3 数据查看
详见 Core Optimization Concepts for Particle Systems。
2.3.1 Stat UNIT
运行游戏,按 ~
键(1 左边那个),然后输入 Stat UNIT
,可以看到下图所示界面:
2.3.2 Stat Particles
运行游戏,按 ~
键(1 左边那个),然后输入 Stat ParticlesOverview
(打了 stat particle 之后能看到还有一些其他选项),可以看到下图所示界面,播放特效后会显示数据:
其中:
GT
- 表示 Game ThreadRT
- 表示 Render Thread
按理说,放一个技能之前是多少,放玩技能,特效都结束之后,这个数还应该是多少,如果结束很久了,这个 CallCount 还是变多了没有变化来,说明一定有特效时长/生命周期有问题。
2.3.3 Stat StartFile
输入 Stat StartFile
,然后正常进行游戏,或者针对性进行特定操作,然后 输入 Stat StopFile
,这时候在 \ARPG\ARPG\Saved\Profiling 目录下就会生成记录文件。
从 Window -> Developer Tools -> Session Frontend,中 Profiler 界面,Load 对应记录文件,就可以打开了。
里边数据很详细,比如 2.3.2 中的 GT concurrent Total
,可以通过搜索,搜出来,双击之后,可以在 Graph View 中看到最大最小,以及平均值。
2.3.4 Content 目录下
在 Content 目录下,可以用 Filters 筛选出 Particle System
,如下图所示:
鼠标悬停到每一个特效资源文件上,会有简略信息的显示:
如果想要按照一些信息进行排序,可以在 Content 目录右下角,View Options
中选择 Columns
,就可以按不同数据进行排序了:
2.4 特效池(WorldPSCPool)
关于特效池,可以看第二篇 —— 【UE4】特效之 Particle System 详解(二)—— 特效池(本文中只需要知道一点,默认释放出来的特效,是没有放入池子管理的)。
三、Particle System 问题记录
这个由于太多了,也会写一篇单独的,
四、参考资料
- Particle System User Guide(官方操作指南 - Cascade 基本术语和知识)
- Particle System Reference
- Unreal Engine 4 Particle Systems Tutorial(轻松上手粒子系统)
- VFX Optimization Guide
- 粒子系统用户指南(官方)
- 粒子系统的关键概念(官方)
- 级联粒子编辑器参考(官方)
- Core Optimization Concepts for Particle Systems(官方)
- Particle System Level of Detail (LOD)(官方)