粒子发射器技术指南
创建新的发射器类型需要自定义的ParticleEmitterInstance
和ParticleModuleTypeData
。 这个指南解释了每项内容的关键部分并描述了创建新自定义发射器类型的步骤。
粒子发射器引用
ParticleEmitterInstance
变量和函数以及ParticleModuleTypeData
类都在此部分中进行了解释。
ParticleEmitterInstance结构体
ParticleEmitterInstance
是一个可以代表ParticleSystemComponent
中的特效实例的单独粒子发射器。
成员变量
ParticleEmitterInstance
结构体包含以下public 变量:
变量 | 概述 |
---|---|
StaticType
|
这是发射器实例的类型标识符。 它可以用于标识发射器以及提供安全投射功能。 |
SpriteTemplate
|
指向建立实例的基础 UParticleSpriteEmitter 模板的指针。 在自定义发射器类型案例中,任何需要的特定数据通常都存储在稍后会在该文档中详细描述的 TypeDataModule 中。
|
Component
|
指向 拥有 这个发射器实例的 UParticleSystemComponent 指针。
|
CurrentLODLevelIndex
|
当前 LOD 关卡集合的索引。 |
CurrentLODLevel
|
指向当前活动的 UParticleLODLevel 的指针。
|
TypeDataOffset
|
在特定数据中 TypeData 净荷的偏移。 使用它可以轻松检索指定给发射器类型的粒子级数据。
|
SubUVDataOffset
|
在特定数据中 SubUV-specific 净荷的偏移。 只有在没有将 subUV 插值模式设置为 NONE (无)的情况下才相关。
|
Location
|
FVector 提供发射器实例的位置。 |
KillOnDeactivate
|
如果为 true (真),会在停用发射器实例的时候将其销毁(删除)。
|
bKillOnCompleted
|
如果为 true (真),会在发射器实例完成它的周期后将其销毁(删除)。
|
ParticleData
|
指向粒子数据数组的指针。 |
ParticleIndices
|
指向粒子索引数组的指针。 用于提供可以使用粒子数据的轮循系统。 |
ModuleOffsetMap
|
指向它们在粒子净荷数据中的偏移量的地图模块指针。 |
InstanceData
|
指向实例级数据数据的指针。 |
InstancePayloadSize
|
实例级数据数组的大小。 |
ModuleInstanceOffsetMap
|
指向它们在实例级数据中的偏移量的地图模块指针。 |
PayloadOffset
|
粒子净荷数据的开始位置的偏移量。 |
ParticleSize
|
粒子的总大小(以字节为单位)。 |
ParticleStride
|
在 ParticleData 数组中的粒子之间的结构体(允许假定对齐粒子数据)。 |
ActiveParticles
|
在发射器中当前活动的粒子数。 |
MaxActiveParticles
|
可以在粒子数据数组中具有的粒子最大数。 |
SpawnFraction
|
最后帧产生中遗留的时间部分。 |
SecondsSinceCreation
|
从实例创建开始经过的秒数。 |
EmitterTime
|
在发射器单个循环中时间的 位置 。 |
OldLocation
|
发射器以前的位置。 |
ParticleBoundingBox
|
发射器的边界盒。 |
BurstFired
|
用于跟踪爆炸触发的元素项的数组。 |
LoopCount
|
- 通过实例完成的循环数。 |
IsRenderDataDirty
|
表示渲染数据是否已经修改的标志。 |
Module_AxisLock
|
如存在,则为 AxisLock 模块。 具有可避免每个 Tick(更新)搜索它。 |
EmitterDuration
|
实例的当前持续时间。 |
EmitterDurations
|
实例的每个 LOD 关卡上持续时间的数组。 |
TrianglesToRender
|
发射器要渲染这个帧的三角形数。 |
MaxVertexIndex
|
渲染时发射器将会访问的最大顶点索引。 |
成员函数
ParticleEmitterInstance 结构体可以包含以下成员函数,它们可以提供覆盖基础功能的机会:
函数 | 概述 |
---|---|
|
将 KillOnDeactivate 标志设置为给定的值。
|
|
将 bKillOnCompleted 标志设置为给定的值。
|
|
假设提供了ParticleEmitter 模板和 父 ParticleSystemComponent ,可以初始化结构体的参数。
|
|
调用它初始化实例。 |
|
调用它可以将粒子数据数组重新调整为 MaxActiveParticles 的给定数。
|
|
使用给定的时间切片更新实例。 如果 bSuppressSpawning 为 true (真),那么不要产生任何新粒子。
|
|
倒回发射器实例。 |
|
为实例返回边界盒。 |
|
为实例更新边界盒。 这里就是为这个帧粒子的最终定位而进行的更新,到现在为止,已经确保发生了所有更新。 |
|
获取发射器需要的粒子级字节数。 |
|
获取指向分配给给定模型的实例级数据的指针。 |
|
计算这个实例中单个粒子的跨距。 |
|
为实例重新设置爆炸列表信息。 |
|
获取当前爆炸速率偏移量 – 人为增加 DeltaTime 导致爆炸。 |
|
在给定当前时间切片 (DeltaTime) 的情况下为实例产生粒子。 将最后从 (OldLeftover) 中遗留的粒子考虑进去。 |
|
处理在这个实例中粒子所需要的任意 pre-spawning(生成前) 操作。 |
|
如果实例已经完成它的运行,那么返回 TRUE(真)。 |
|
处理在这个实例中粒子所需要的任意 post-spawning(生成后) 操作。 |
|
销毁所有销毁的粒子 – 只需从活动数组中将其删除。 |
|
从场景中删除实例时会调用它。 |
|
在给定索引处获取粒子。 |
|
获取渲染这个实例这个帧的动态数据。 |
|
获取发射器实例分配的内存大小 - 进行内存跟踪。 |
ParticleModuleTypeDataBase类
ParticleModuleTypeDataBase
类可以提供在创建一个 ParticleSystem 供在引擎中使用时生成自定义发射器实例的机制。 例如,ParticleModuleTypeDataMesh
类最后结果会为 ParticleSystem 而创建 FParticleMeshEmitterInstance
。
成员函数
ParticleModuleTypeDataBase
结构体会包含以下可以协助生成自定义发射器的 public 函数:
函数 | 概述 |
---|---|
|
它对于覆盖在 UE4 粒子系统中创建的发射器实例非常重要。 在一个实例化的 UParticleEmitter 中发现 TypeData 模型时调用这个函数。 在这个函数中,应该创建并返回预期的 FParticleEmitterInstance。 |
|
在首次创建这个模型时调用它。 这个函数允许您设置合理的默认值。 |
|
在发射器实例的 PreSpawn 函数中调用,这些函数允许刚刚产生的粒子进行特定 TypeDataModule 设置。 |
|
在更新任何发射器实例之前调用,这个函数可以处理任何需要在使用发射器中包含的每个模型更新粒子之前进行的任何更新。 |
|
在更新任何发射器实例之后调用,这个函数可以处理任何需要在使用发射器中包含的每个模型更新粒子之后进行的任何更新。 |
|
可以覆盖在粒子发射器上出现的屏幕对齐标志。 目前只供网格物体发射器使用。 |
示例粒子发射器
编写自定义发射器实例为两步过程。 第一步,需要创建将会为您的发射器实例提供特定数据的 TypeDataModule
,并且在适当的时间生成它。 例如,会创建一个发射器实例,它可以不断执行发射器实例以及‘父’粒子系统组件的旋转量。
TypeDataModule声明
第一步是创建会生成新的发射器实例类型的TypeDataModule
。
UCLASS(editinlinenew, collapsecategories, hidecategories=Object)
public class UParticleModuleTypeDataSpinner : public UParticleModuleTypeDataBase
{
/**
* 在给定时间要执行发射器实例的数量
* (在全部旋转量中)。
*/
UPROPERTY(Category=Spinner)
rawdistributionvector Spin;
#if CPP
/**
* 创建自定义 ParticleEmitterInstance。
*
* @param InEmitterParent UParticleEmitter 可以具有这个 TypeData 模型。
* @param InComponent UParticleSystemComponent 可以‘拥有’正在进行创建的发射器实例。
* @return FParticleEmitterInstance* 创建发射器实例。
*/
virtual FParticleEmitterInstance* CreateInstance(UParticleEmitter* InEmitterParent, UParticleSystemComponent* InComponent);
#endif
}
TypeDataModule的实现
TypeDataModule
的构造函数创建UDistributionVectorConstant
以指派给Spin
变量。
UParticleModuleTypeDataSpinner::UParticleModuleTypeDataSpinner(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
UDistributionVectorConstant* DistributionSpin = ConstructorHelpers::CreateDefaultSubobject<UDistributionVectorConstant>(this, TEXT("DistributionSpin"));
DistributionSpin->Constant = FVector(0.0f, 0.0f, 0.0f);
Spin.Distribution = DistributionSpin;
}
CreateInstance()
函数将会由具有发射器实例的 ParticleSystemComponent
进行调用。 在这里 TypeDataModule
可以创建任何类型的 ParticleEmitterInstance
供系统使用的。
FParticleEmitterInstance* UParticleModuleTypeDataSpinner::CreateInstance(UParticleEmitter* InEmitterParent, UParticleSystemComponent* InComponent)
{
// 创建我们的 Spinner 发射器实例。
FParticleSpinnerEmitterInstance* SpinnerInst = ::new FParticleSpinnerEmitterInstance();
if (SpinnerInst)
{
// 初始化发射器的参数。
SpinnerInst->InitParameters(InEmitterParent, InComponent);
return SpinnerInst;
}
// 如果失败。 会返回 NULL 可以生成默认平面发射器或断言。
return NULL;
}
在这个示例中,将会生成一个 FParticleSpinnerEmitterInstance
的实例。 它从 FParticleSpriteEmitterInstance
衍生而来,可以尽量多地利用现有代码。
粒子发射器声明
FParticleSpinnerEmitterInstance
自定义的发射器实例结构体定义如下:
struct FParticleSpinnerEmitterInstance : public FParticleSpriteEmitterInstance
{
/** 指向旋转器 TypeDatModule 的指针。 */
UParticleModuleTypeDataSpinner* SpinnerTypeData;
/** 在 Tick(更新)调用过程中使用的旋转量。 */
FVector CurrentRotation;
/** 分量的旋转量。 */
FRotator ComponentRotation;
/** 构造函数 */
FParticleSpinnerEmitterInstance();
virtual void InitParameters(UParticleEmitter* InTemplate, UParticleSystemComponent* InComponent, bool bClearResources = true);
virtual void Tick(float DeltaTime, bool bSuppressSpawning);
virtual void UpdateBoundingBox(float DeltaTime);
/**
* 调整分量旋转量以便将实例旋转量考虑进去。
*/
void AdjustComponentRotation();
/**
* 恢复分量旋转量。
*/
void RestoreComponentRotation();
};
FParticleSpinnerEmitterInstance
中包含以下成员变量:
变量 | 概述 |
---|---|
SpinnerTypeData
|
指向 UParticleModuleTypeDataSpinner 的指针。 这样做每次我们需要访问它的时候可以直接避免转换 TypeData 模型。
|
CurrentRotation
|
FVector 可以跟踪发射器实例当前的旋转量。 在 Tick() /TickEditor() 中获得以更新旋转量,并存储从而在 UpdateBoundingBox() 函数中使用。
|
粒子发射器实现
为我们的自定义发射器实例执行以下成员函数:
函数 | |||||
---|---|---|---|---|---|
|
|||||
|
|||||
|
Tick() 函数主要负责在实例中产生和更新粒子。 首先,它会使用 EmitterTime 从 SpinnerTypeData 分布中获取当前旋转量。 因为 父 分量的 LocalToWorld 可以在各种模块的 Spawn() /Update() 函数中使用,所以我们需要确保将发射器实例旋转量考虑进去。 这可以通过保存分量的 Rotation (旋转量)然后将发射器实例量添加到它完成。 这样就会将分量变换更新为包括这个新的旋转量。 然后通过调用超级 Tick() (更新)函数将发射器实例 更新为 与通用实例相同: 这样就可以恢复分量 Rotation (旋转量)。
|
||||
|
在这个案例中必须覆盖 UpdateBoundingBox() 函数才能确保在 bUseLocalSpace 为true 的时候考虑发射器实例。
|
||||
|
AdjustComponentRotation() 函数会更改分量 LocalToWorld 以说明发射器实例旋转量。
|
||||
|
RestoreComponentRotation() 函数会从组件 LocalToWorld 中删除发射器实例旋转量。
|
结果
下面的屏幕截图会在操作过程中演示 Spinner 发射器实例。 设置如下所示:
将 Spin 分布设置为其中一个点位于 (Time=0,X=0,Y=0,Z=0) 另一个点位于 (Time=1,X=0,Y=0,Z=1) 的常量曲线,它可以使实例在发射器的声明周期过程中以不同的速率围绕 Z 轴进行旋转。
将 InitialVelocity 模块与一个设置为 (X=100,Y=100,Z=100) 的 Constant Distribution(常数分布)联合使用,这样所有的粒子将会以直线流的方式发射(不考虑实例的旋转)。
将 InitialColor 模块与设置为其中一个点为 (Time=0,R=1,G=0,B=0) 另一个点为 (Time=1,R=0,G=0,B=1) 的 StartColor 联合使用,这样可以使发射器的生命周期过程中所发射的粒子从红色变为蓝色。