第9章 Niagara与C++结合应用
9.1 Niagara的C++ API基础
9.1.1 C++ API概述
Niagara提供了丰富的C++ API,用于在C++代码中控制和管理Niagara粒子系统。这些API包括:
- 核心类
UNiagaraSystem:Niagara粒子系统类,用于定义粒子系统的属性和行为UNiagaraEmitter:Niagara粒子发射器类,用于定义粒子的生成和更新UNiagaraComponent:Niagara组件类,用于在场景中使用Niagara系统-
UNiagaraDataInterface:Niagara数据接口类,用于在Niagara系统和外部数据之间建立连接 -
模块类
UNiagaraModule:Niagara模块基类,所有Niagara模块都继承自这个类UNiagaraGenerateModule:Niagara生成模块类,用于控制粒子的生成UNiagaraUpdateModule:Niagara更新模块类,用于控制粒子的更新-
UNiagaraRenderModule:Niagara渲染模块类,用于控制粒子的渲染 -
函数类
UNiagaraFunction:Niagara函数基类,所有Niagara函数都继承自这个类-
UNiagaraFunctionLibrary:Niagara函数库类,提供了各种实用的函数 -
参数类
UNiagaraParameterCollection:Niagara参数集合类,用于管理Niagara系统的参数UNiagaraParameterStore:Niagara参数存储类,用于存储和管理Niagara系统的参数
9.1.2 C++ API的使用方法
在C++代码中使用Niagara API需要包含相应的头文件,并使用正确的命名空间。
包含头文件:
#include "NiagaraSystem.h"
#include "NiagaraEmitter.h"
#include "NiagaraComponent.h"
#include "NiagaraDataInterface.h"
#include "NiagaraModule.h"
#include "NiagaraFunctionLibrary.h"
#include "NiagaraParameterCollection.h"
#include "NiagaraParameterStore.h"
命名空间:
Niagara的C++ API主要在UNiagara命名空间中,但大多数类和函数直接在全局命名空间中。
9.1.3 C++与蓝图的交互
在C++代码中,可以通过以下方式与蓝图进行交互:
- 蓝图可调用函数
- 使用
UFUNCTION(BlueprintCallable)宏定义蓝图可调用函数 -
例如:
cpp UFUNCTION(BlueprintCallable, Category = "Niagara") void ActivateNiagaraSystem(); -
蓝图可重写函数
- 使用
UFUNCTION(BlueprintNativeEvent)宏定义蓝图可重写函数 -
例如:
cpp UFUNCTION(BlueprintNativeEvent, Category = "Niagara") void OnNiagaraSystemActivated(); -
蓝图事件
- 使用
UFUNCTION(BlueprintImplementableEvent)宏定义蓝图事件 - 例如:
cpp UFUNCTION(BlueprintImplementableEvent, Category = "Niagara") void OnNiagaraSystemDeactivated();
9.2 C++控制Niagara系统
9.2.1 创建和配置Niagara组件
在C++代码中,可以通过以下方式创建和配置Niagara组件:
- 创建Niagara组件
- 使用
CreateDefaultSubobject函数创建Niagara组件 -
例如:
cpp UNiagaraComponent* NiagaraComponent = CreateDefaultSubobject<UNiagaraComponent>(TEXT("NiagaraComponent")); -
配置Niagara组件
- 设置Niagara系统
- 设置自动激活属性
- 设置循环属性
-
例如:
cpp NiagaraComponent->SetAsset(LoadObject<UNiagaraSystem>(nullptr, TEXT("/Game/Particles/MyNiagaraSystem.MyNiagaraSystem"))); NiagaraComponent->SetAutoActivate(true); NiagaraComponent->SetLooping(true); -
附加Niagara组件
- 使用
AttachToComponent函数将Niagara组件附加到其他组件上 - 例如:
cpp NiagaraComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
9.2.2 激活与停止Niagara系统
在C++代码中,可以通过以下方式激活与停止Niagara系统:
- 激活Niagara系统
- 使用
Activate函数激活Niagara系统 -
例如:
cpp NiagaraComponent->Activate(); -
停止Niagara系统
- 使用
Deactivate函数停止Niagara系统 -
例如:
cpp NiagaraComponent->Deactivate(); -
重置Niagara系统
- 使用
ResetSystem函数重置Niagara系统 -
例如:
cpp NiagaraComponent->ResetSystem(); -
暂停与恢复Niagara系统
- 使用
SetPaused函数暂停或恢复Niagara系统 - 例如:
cpp NiagaraComponent->SetPaused(true); // 暂停 NiagaraComponent->SetPaused(false); // 恢复
9.2.3 修改Niagara系统属性
在C++代码中,可以通过以下方式修改Niagara系统的属性:
- 设置属性值
- 使用
SetFloatParameter、SetVectorParameter等函数设置属性值 -
例如:
cpp NiagaraComponent->SetFloatParameter(TEXT("ParticleSize"), 10.0f); NiagaraComponent->SetVectorParameter(TEXT("ParticleColor"), FVector(1.0f, 0.0f, 0.0f)); -
获取属性值
- 使用
GetFloatParameter、GetVectorParameter等函数获取属性值 -
例如:
cpp float ParticleSize = NiagaraComponent->GetFloatParameter(TEXT("ParticleSize")); FVector ParticleColor = NiagaraComponent->GetVectorParameter(TEXT("ParticleColor")); -
设置变量值
- 使用
SetVariableFloat、SetVariableVector等函数设置变量值 -
例如:
cpp NiagaraComponent->SetVariableFloat(TEXT("Speed"), 200.0f); NiagaraComponent->SetVariableVector(TEXT("Direction"), FVector(0.0f, 0.0f, 1.0f)); -
获取变量值
- 使用
GetVariableFloat、GetVariableVector等函数获取变量值 - 例如:
cpp float Speed = NiagaraComponent->GetVariableFloat(TEXT("Speed")); FVector Direction = NiagaraComponent->GetVariableVector(TEXT("Direction"));
9.2.4 生成与销毁Niagara粒子
在C++代码中,可以通过以下方式生成与销毁Niagara粒子:
- 生成粒子
- 使用
SpawnEmitterAtLocation、SpawnEmitterAttached等函数生成粒子 -
例如:
cpp UNiagaraSystem* NiagaraSystem = LoadObject<UNiagaraSystem>(nullptr, TEXT("/Game/Particles/Explosion.Explosion")); FVector Location = GetActorLocation(); FRotator Rotation = GetActorRotation(); UNiagaraComponent* NiagaraComponent = UNiagaraFunctionLibrary::SpawnEmitterAtLocation(this, NiagaraSystem, Location, Rotation); -
销毁粒子
- 使用
DestroyComponent函数销毁Niagara组件 - 例如:
cpp NiagaraComponent->DestroyComponent();
9.3 C++创建自定义Niagara模块
9.3.1 自定义模块的概念
自定义Niagara模块是指使用C++代码创建的Niagara模块,可以扩展Niagara系统的功能。自定义模块可以:
- 实现复杂的粒子行为
- 如自定义物理模拟、AI行为等
-
提供更高的灵活性和控制力
-
优化性能
- 对于计算密集型的操作,可以使用C++代码优化性能
-
减少GPU和CPU的负担
-
与外部系统集成
- 如与游戏逻辑、AI系统、物理引擎等集成
- 扩展Niagara系统的应用范围
9.3.2 创建自定义模块的步骤
创建自定义Niagara模块的步骤如下:
- 创建C++类
- 继承自UNiagaraModule或其子类
-
例如:
cpp UCLASS(Blueprintable, Category = "Niagara") class MYGAME_API UMyNiagaraModule : public UNiagaraModule { GENERATED_BODY() }; -
实现模块功能
- 重写
OnGenerate、OnUpdate、OnRender等函数 - 实现模块的核心功能
-
例如:
cpp virtual void OnUpdate(FNiagaraEmitterInstance* EmitterInstance, TArray<FNiagaraParticleData>& ParticleData, float DeltaTime) override { // 实现粒子更新逻辑 } -
注册模块
- 在Niagara模块注册表中注册自定义模块
-
例如:
cpp IMPLEMENT_NIAGARA_MODULE(UMyNiagaraModule) -
编译和测试
- 编译项目
- 在Niagara编辑器中使用自定义模块
- 测试模块功能
9.3.3 自定义模块示例
以下是一个自定义Niagara模块的示例,用于实现粒子的自定义物理模拟:
// MyNiagaraPhysicsModule.h
#pragma once
#include "NiagaraModule.h"
#include "MyNiagaraPhysicsModule.generated.h"
UCLASS(Blueprintable, Category = "Niagara")
class MYGAME_API UMyNiagaraPhysicsModule : public UNiagaraModule
{
GENERATED_BODY()
public:
// 重力强度
UPROPERTY(EditAnywhere, Category = "Physics")
float GravityStrength;
// 阻力系数
UPROPERTY(EditAnywhere, Category = "Physics")
float DragCoefficient;
// 初始速度
UPROPERTY(EditAnywhere, Category = "Physics")
FVector InitialVelocity;
// 构造函数
UMyNiagaraPhysicsModule();
// 生成函数
virtual void OnGenerate(FNiagaraEmitterInstance* EmitterInstance, TArray<FNiagaraParticleData>& ParticleData, float DeltaTime) override;
// 更新函数
virtual void OnUpdate(FNiagaraEmitterInstance* EmitterInstance, TArray<FNiagaraParticleData>& ParticleData, float DeltaTime) override;
};
// MyNiagaraPhysicsModule.cpp
#include "MyNiagaraPhysicsModule.h"
// 构造函数
UMyNiagaraPhysicsModule::UMyNiagaraPhysicsModule()
{
GravityStrength = -980.0f;
DragCoefficient = 0.1f;
InitialVelocity = FVector(0.0f, 0.0f, 0.0f);
}
// 生成函数
void UMyNiagaraPhysicsModule::OnGenerate(FNiagaraEmitterInstance* EmitterInstance, TArray<FNiagaraParticleData>& ParticleData, float DeltaTime)
{
for (FNiagaraParticleData& Particle : ParticleData)
{
// 设置初始速度
Particle.Velocity = InitialVelocity;
}
}
// 更新函数
void UMyNiagaraPhysicsModule::OnUpdate(FNiagaraEmitterInstance* EmitterInstance, TArray<FNiagaraParticleData>& ParticleData, float DeltaTime)
{
for (FNiagaraParticleData& Particle : ParticleData)
{
// 应用重力
Particle.Velocity.Z += GravityStrength * DeltaTime;
// 应用阻力
Particle.Velocity *= (1.0f - DragCoefficient * DeltaTime);
// 更新位置
Particle.Position += Particle.Velocity * DeltaTime;
}
}
// 注册模块
IMPLEMENT_NIAGARA_MODULE(UMyNiagaraPhysicsModule)
9.4 C++与Niagara的性能优化
9.4.1 性能优化策略
在使用C++与Niagara结合应用时,应遵循以下性能优化策略:
- 减少粒子数量
- 尽量减少粒子数量
- 使用LOD技术
-
距离远时减少粒子数量
-
优化粒子计算
- 使用C++代码优化粒子计算
- 避免在每一帧都更新所有粒子
-
使用SIMD指令优化计算
-
使用GPU计算
- 将计算密集型的操作转移到GPU上
- 使用Compute Shader优化性能
-
减少CPU和GPU之间的数据传输
-
资源管理
- 预加载Niagara系统和资源
- 使用对象池技术管理Niagara组件
-
及时销毁不再使用的Niagara组件
-
内存优化
- 减少内存分配和释放
- 使用内存池管理粒子数据
- 优化数据结构,减少内存占用
9.4.2 性能分析工具
在优化Niagara系统性能时,可以使用以下性能分析工具:
- UE5内置性能分析工具
- Stat Niagara:显示Niagara系统的性能统计信息
- Stat Unit:显示游戏的帧率、CPU和GPU使用率等
-
ProfileGPU:分析GPU的性能瓶颈
-
第三方性能分析工具
- NVIDIA Nsight:分析GPU性能
- AMD Radeon GPU Profiler:分析AMD GPU性能
- Intel VTune Profiler:分析CPU性能
9.4.3 性能优化示例
以下是一个使用C++代码优化Niagara系统性能的示例:
// 优化前:在每一帧都更新所有粒子的位置
void UMyGameCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 更新所有粒子的位置
for (UNiagaraComponent* NiagaraComponent : NiagaraComponents)
{
FVector NewLocation = GetActorLocation();
NiagaraComponent->SetVectorParameter(TEXT("Location"), NewLocation);
}
}
// 优化后:只有当位置变化超过阈值时才更新粒子的位置
void UMyGameCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 检查位置是否变化超过阈值
FVector CurrentLocation = GetActorLocation();
if (FVector::Distance(CurrentLocation, LastLocation) > LocationUpdateThreshold)
{
// 更新所有粒子的位置
for (UNiagaraComponent* NiagaraComponent : NiagaraComponents)
{
NiagaraComponent->SetVectorParameter(TEXT("Location"), CurrentLocation);
}
// 更新最后位置
LastLocation = CurrentLocation;
}
}
9.5 案例:C++与Niagara结合实现高级效果
9.5.1 案例:自定义物理模拟
效果描述:使用C++代码创建自定义物理模拟模块,实现粒子的复杂物理行为。
实现步骤:
- 创建自定义Niagara模块
- 创建UMyNiagaraPhysicsModule类,继承自UNiagaraModule
- 实现OnGenerate和OnUpdate函数
-
配置物理参数(如重力强度、阻力系数等)
-
创建Niagara系统
- 打开Niagara编辑器
- 创建新的Niagara系统,命名为"CustomPhysicsSystem"
-
添加发射器,命名为"CustomPhysicsEmitter"
-
配置Niagara系统
- 添加自定义模块UMyNiagaraPhysicsModule
- 配置模块参数(如重力强度、阻力系数等)
-
添加Sprite Renderer模块,设置材质和精灵大小
-
创建C++ Actor
- 创建ACustomPhysicsActor类,继承自AActor
- 添加NiagaraComponent,设置NiagaraSystem为CustomPhysicsSystem
-
实现Actor的核心功能
-
实现Actor逻辑
- 在构造函数中初始化NiagaraComponent
- 在BeginPlay函数中激活Niagara系统
-
在Tick函数中更新Niagara系统的参数
-
测试与优化
- 在场景中放置ACustomPhysicsActor
- 运行游戏,观察粒子的物理行为
- 调整参数以获得最佳效果
代码示例:
// ACustomPhysicsActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NiagaraComponent.h"
#include "CustomPhysicsActor.generated.h"
UCLASS()
class MYGAME_API ACustomPhysicsActor : public AActor
{
GENERATED_BODY()
public:
// 构造函数
ACustomPhysicsActor();
protected:
// 组件
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UNiagaraComponent* NiagaraComponent;
// Niagara系统
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Niagara")
UNiagaraSystem* NiagaraSystem;
// 物理参数
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float GravityStrength;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float DragCoefficient;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
FVector InitialVelocity;
// 生命周期
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
};
// ACustomPhysicsActor.cpp
#include "CustomPhysicsActor.h"
// 构造函数
ACustomPhysicsActor::ACustomPhysicsActor()
{
// 创建根组件
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
// 创建Niagara组件
NiagaraComponent = CreateDefaultSubobject<UNiagaraComponent>(TEXT("NiagaraComponent"));
NiagaraComponent->SetupAttachment(RootComponent);
// 设置默认值
GravityStrength = -980.0f;
DragCoefficient = 0.1f;
InitialVelocity = FVector(0.0f, 0.0f, 500.0f);
}
// BeginPlay
void ACustomPhysicsActor::BeginPlay()
{
Super::BeginPlay();
// 设置Niagara系统
if (NiagaraSystem)
{
NiagaraComponent->SetAsset(NiagaraSystem);
}
// 设置物理参数
NiagaraComponent->SetFloatParameter(TEXT("GravityStrength"), GravityStrength);
NiagaraComponent->SetFloatParameter(TEXT("DragCoefficient"), DragCoefficient);
NiagaraComponent->SetVectorParameter(TEXT("InitialVelocity"), InitialVelocity);
// 激活Niagara系统
NiagaraComponent->Activate();
}
// Tick
void ACustomPhysicsActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 更新Niagara系统的位置
FVector NewLocation = GetActorLocation();
NiagaraComponent->SetVectorParameter(TEXT("Location"), NewLocation);
}
9.5.2 案例:与AI系统集成
效果描述:将Niagara粒子系统与AI系统集成,实现智能粒子效果。
实现步骤:
- 创建AI系统
- 创建AAIController子类,实现AI行为
-
创建ACharacter子类,实现角色逻辑
-
创建Niagara系统
- 打开Niagara编辑器
- 创建新的Niagara系统,命名为"AIParticleSystem"
-
添加发射器,命名为"AIParticleEmitter"
-
配置Niagara系统
- 添加生成模块、更新模块和渲染模块
-
配置粒子的生成、更新和渲染
-
创建C++ Actor
- 创建AAIParticleActor类,继承自AActor
- 添加NiagaraComponent和AIController组件
-
实现Actor的核心功能
-
实现Actor逻辑
- 在构造函数中初始化组件
- 在BeginPlay函数中激活Niagara系统和AI控制器
-
在Tick函数中更新Niagara系统的参数
-
测试与优化
- 在场景中放置AAIParticleActor
- 运行游戏,观察AI控制的粒子效果
- 调整参数以获得最佳效果
代码示例:
// AAIParticleActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AIController.h"
#include "NiagaraComponent.h"
#include "AIParticleActor.generated.h"
UCLASS()
class MYGAME_API AAIParticleActor : public AActor
{
GENERATED_BODY()
public:
// 构造函数
AAIParticleActor();
protected:
// 组件
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UNiagaraComponent* NiagaraComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UBoxComponent* CollisionComponent;
// AI控制器
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
TSubclassOf<AAIController> AIControllerClass;
UPROPERTY(BlueprintReadOnly, Category = "AI")
AAIController* AIController;
// Niagara系统
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Niagara")
UNiagaraSystem* NiagaraSystem;
// AI参数
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
float AISpeed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
float AIAcceleration;
// 生命周期
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
// 碰撞事件
UFUNCTION()
void OnCollisionBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnCollisionEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
// AAIParticleActor.cpp
#include "AIParticleActor.h"
#include "Components/BoxComponent.h"
// 构造函数
AAIParticleActor::AAIParticleActor()
{
// 创建根组件
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
// 创建碰撞组件
CollisionComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("CollisionComponent"));
CollisionComponent->SetupAttachment(RootComponent);
CollisionComponent->SetBoxExtent(FVector(100.0f, 100.0f, 100.0f));
CollisionComponent->OnComponentBeginOverlap.AddDynamic(this, &AAIParticleActor::OnCollisionBeginOverlap);
CollisionComponent->OnComponentEndOverlap.AddDynamic(this, &AAIParticleActor::OnCollisionEndOverlap);
// 创建Niagara组件
NiagaraComponent = CreateDefaultSubobject<UNiagaraComponent>(TEXT("NiagaraComponent"));
NiagaraComponent->SetupAttachment(RootComponent);
// 设置默认值
AISpeed = 100.0f;
AIAcceleration = 500.0f;
}
// BeginPlay
void AAIParticleActor::BeginPlay()
{
Super::BeginPlay();
// 生成AI控制器
if (AIControllerClass)
{
AIController = GetWorld()->SpawnActor<AAIController>(AIControllerClass, GetActorLocation(), GetActorRotation());
if (AIController)
{
AIController->Possess(this);
}
}
// 设置Niagara系统
if (NiagaraSystem)
{
NiagaraComponent->SetAsset(NiagaraSystem);
}
// 设置AI参数
NiagaraComponent->SetFloatParameter(TEXT("AISpeed"), AISpeed);
NiagaraComponent->SetFloatParameter(TEXT("AIAcceleration"), AIAcceleration);
// 激活Niagara系统
NiagaraComponent->Activate();
}
// Tick
void AAIParticleActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 更新Niagara系统的位置和旋转
FVector NewLocation = GetActorLocation();
FRotator NewRotation = GetActorRotation();
NiagaraComponent->SetVectorParameter(TEXT("Location"), NewLocation);
NiagaraComponent->SetVectorParameter(TEXT("Rotation"), FVector(NewRotation.Roll, NewRotation.Pitch, NewRotation.Yaw));
}
// 碰撞开始事件
void AAIParticleActor::OnCollisionBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// 处理碰撞事件
if (OtherActor->IsA(APlayerCharacter::StaticClass()))
{
// 激活特殊效果
NiagaraComponent->SetFloatParameter(TEXT("SpecialEffectEnabled"), 1.0f);
}
}
// 碰撞结束事件
void AAIParticleActor::OnCollisionEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
// 处理碰撞结束事件
if (OtherActor->IsA(APlayerCharacter::StaticClass()))
{
// 停止特殊效果
NiagaraComponent->SetFloatParameter(TEXT("SpecialEffectEnabled"), 0.0f);
}
}
本章小结
本章介绍了Niagara与C++的结合应用,包括Niagara的C++ API基础、C++控制Niagara系统、C++创建自定义Niagara模块、C++与Niagara的性能优化等内容。通过本章的学习,读者应该能够理解Niagara的C++ API的使用方法,并能够使用C++代码控制Niagara粒子系统,创建自定义的Niagara模块,以及优化Niagara系统的性能。
下一章将介绍高级篇的内容,包括Niagara的高级特性与优化、运动图形与Niagara的高级应用、性能优化与最佳实践等。