粒子模块用于设置粒子的各种属性,如颜色和速度等。
粒子模块基类为UParticleModule,所有的粒子模块都是继承自这个基类,它有两个虚函数Spawn和Update,我们一般重载这两个函数即可。
virtual void Spawn(FParticleEmitterInstance* Owner, int32 Offset, float SpawnTime, FBaseParticle* ParticleBase);
virtual void Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime);
粒子模块一般会继承两级,第一级用于分类,第二级用于具体的实现,如UParticleModuleColorBase为第一级,在右键菜单中显示为“Color”一级菜单,UParticleModuleColorOverLife继承自UParticleModuleColorBase为第二级,在右键菜单中显示为Color下的二级菜单“Color Over Life”。
在这个例子中实现UParticleModuleCustomBase和UParticleModuleCustomShape两级,UParticleModuleCustomShape通过设定粒子的初始速度实现一个自定义的形状。在右键菜单中分别显示为一级“Custom”和二级“Shape”
UCLASS(editinlinenew, hidecategories=Object, abstract, meta=(DisplayName = "Custom"))
class UParticleModuleCustomBase : public UParticleModule
{
GENERATED_UCLASS_BODY()
};
UCLASS(editinlinenew, collapsecategories, hidecategories = Object, meta = (DisplayName = "Shape"))
class UParticleModuleCustomShape : public UParticleModuleCustomBase
{
GENERATED_UCLASS_BODY()
public:
virtual void Spawn(FParticleEmitterInstance* Owner, int32 Offset, float SpawnTime, FBaseParticle* ParticleBase);
virtual void Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime);
};
以下为实现部分的主要代码:
#define COS(degree) (FMath::Cos(FMath::DegreesToRadians(degree)))
#define SIN(degree) (FMath::Sin(FMath::DegreesToRadians(degree)))
UParticleModuleCustomShape::UParticleModuleCustomShape(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//同时需要Spawn和Update两个函数
bSpawnModule = true;
bUpdateModule = true;
}
void UParticleModuleCustomShape::Spawn(FParticleEmitterInstance* Owner, int32 Offset, float SpawnTime, FBaseParticle* ParticleBase)
{
SPAWN_INIT;
{
float p = 3.0 / 2;
int32 degree = FMath::RandRange(0, 360 * 4);//在周期内随机获取一个角度
//以下为花瓣曲线方程,可以换成其他的方程,生成不同的形状,其中p为参数可以控制花瓣数和周期
float y = SIN(p * degree) * COS(degree);
float z = SIN(p * degree) * SIN(degree);
Particle.Velocity = 100 * FVector(0, y, z);//在yz平面生成,并将形状扩大100倍
Particle.BaseVelocity = Particle.Velocity;
}
}
void UParticleModuleCustomShape::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime)
{
BEGIN_UPDATE_LOOP;
{
Particle.Velocity *= (1 - Particle.RelativeTime * Particle.RelativeTime);//速度随时间衰减
}
END_UPDATE_LOOP;
}
在Spawn函数中有一个宏SPAWN_INIT,将其展开之后的代码是:
check((Owner != NULL) && (Owner->Component != NULL));
const int32 ActiveParticles = Owner->ActiveParticles;
const uint32 ParticleStride = Owner->ParticleStride;
uint32 CurrentOffset = Offset;
FBaseParticle& Particle = *(ParticleBase);
同样展开BEGIN_UPDATE_LOOP和END_UPDATE_LOOP,是一个循环:
{
check((Owner != NULL) && (Owner->Component != NULL));
int32& ActiveParticles = Owner->ActiveParticles;
uint32 CurrentOffset = Offset;
const uint8* ParticleData = Owner->ParticleData;
const uint32 ParticleStride = Owner->ParticleStride;
uint16* ParticleIndices = Owner->ParticleIndices;
for(int32 i=ActiveParticles-1; i>=0; i--)
{
const int32 CurrentIndex = ParticleIndices[i];
const uint8* ParticleBase = ParticleData + CurrentIndex * ParticleStride;
FBaseParticle& Particle = *((FBaseParticle*) ParticleBase);
if ((Particle.Flags & STATE_Particle_Freeze) == 0)
{
//自己的代码
}
CurrentOffset = Offset;
}
}
在Spawn中随机取得花瓣曲线上一个点,将其作为该粒子的速度,只要粒子数够多就可以均匀分布在曲线上,形成一个花瓣曲线。在Update中让粒子速度以相对时间的平方衰减,并在粒子消失之时变成静止。
这两个类定义好之后,打开编辑器,定义一个粒子系统,并在一个粒子实例上右键添加Custom下的Shape模块,并设置好相关的参数(最好将Spawn模块中的Rate设置为0,Burst下的Burst List中的Count设置为需要生成的粒子数,这样粒子就是一次性生成,而不是连续生成),这时粒子会形成花瓣曲线的形式(注:由于粒子系统的计算方式是以模块从上到下的方式,所以在Shape模块后面不能再有改变粒子速度的模块,如InitVelocity)。
利用该模块可以制作自定义形状的烟花类型,将“内容示例”中的烟花粒子修改并添加该模块后制作出如下各种形状的烟花: