Niagara特效资产检查

在UE4中,如果想做一个编辑器检查功能,批量对所有NiagaraSystem资产进行检查,需要获取到特效内部发射器上的Module的某些具体配置,比如ParticleState上的 KillParticlesWhenLifetimeHasElapsed,用于检查是不是有一致发射,然后持续泄露的特效等。

因为要拿到Module上的信息,需要SystemViewModel,之前的做法是,在代码中 GetExistingViewModelForSystem,如果没有(也就是没有在编辑器中打开这个特效),则需要 Make一个然后Initialize,通过 SystemViewModel 获取 UNiagaraStackItemGroup,然后通过 GetUnfilteredChildrenOfType 获取 UNiagaraStackModuleItem,然后获取 UNiagaraStackFunctionInputCollection 数组,找到对应的 UNiagaraStackFunctionInputCollection,再根据参数的索引找到 UNiagaraStackFunctionInput,然后 >GetLocalValueStruct()->GetStructMemory() 的方式获取实际选项配置的值,进行判断。

想问下UE5中有没有什么优化,有什么更方便的批量检查,或者说单个资产检查配置的方式

[Attachment Removed]

你好,

UE5的Niagara Effect Type可以设置Validation Rules, 对不同类型的特效设置不同的资产检查规则. 除了如下默认的检查, 也很方便做规则扩展, 可以参考这篇文章看看.

[Image Removed]​

[Attachment Removed]

比如我想获取不是NiagaraSystem上的参数,而是EmitterState 这个Module的 LoopBehavior配置,判断如果是Infinite,那么再看 ParticleState 上的 KillParticlesWhenLifetimeHasElapsed 是不是没选,这样来判断会不会有持续性的粒子泄露呢

[Attachment Removed]

如果用扩展Validation Rules的方式做, 5.7上, 可以在NiagaraValidationRules.h类似下面加一个规则:

UCLASS(Category = "Validation", DisplayName = "Validate Particle State")
class UNiagaraValidationRule_NoInfinitePariticles : public UNiagaraValidationRule
{
	GENERATED_BODY()
public:
	virtual void CheckValidity(const FNiagaraValidationContext& Context, TArray<FNiagaraValidationResult>& OutResults) const override;
};

NiagaraValidationRules.cpp中:

void UNiagaraValidationRule_NoInfinitePariticles::CheckValidity(const FNiagaraValidationContext& Context, TArray<FNiagaraValidationResult>& Results) const
{
	UNiagaraStackModuleItem* SourceModule = Cast<UNiagaraStackModuleItem>(Context.Source);
	if (SourceModule && SourceModule->GetIsEnabled())
	{
		TArray<UNiagaraStackFunctionInput*> ModuleInputs;
		SourceModule->GetParameterInputs(ModuleInputs);
 
		bool KillParticleWhenLifetimeHasElapsed = true;
		for (UNiagaraStackFunctionInput* Input : ModuleInputs)
		{
			if (Input->GetInputParameterHandle().GetName() == FName("Kill Particles When Lifetime Has Elapsed"))
			{
				KillParticleWhenLifetimeHasElapsed = *(bool*)Input->GetLocalValueStruct()->GetStructMemory();
				break;
			}
		}
 
		if (KillParticleWhenLifetimeHasElapsed)
			return;
 
		UNiagaraStackModuleItem* EmitterStateModule = nullptr;
		for (const TSharedRef<FNiagaraEmitterHandleViewModel>& EmitterHandleModel : Context.ViewModel->GetEmitterHandleViewModels())
		{
			if (EmitterHandleModel->GetIsEnabled() && EmitterHandleModel->GetEmitterViewModel() == SourceModule->GetEmitterViewModel())
			{
				TArray<UNiagaraStackModuleItem*> ModuleItems = NiagaraValidation::GetStackEntries<UNiagaraStackModuleItem>(EmitterHandleModel->GetEmitterStackViewModel());
				for (UNiagaraStackModuleItem* Item : ModuleItems)
				{
					UNiagaraNodeFunctionCall& FuncCall = Item->GetModuleNode();
					if (FuncCall.GetFunctionName() == FString("EmitterState"))
					{
						EmitterStateModule = Item;
						break;
					}
				}
			}
		}
 
		if (!EmitterStateModule)
			return;
 
		EmitterStateModule->GetParameterInputs(ModuleInputs);
		for (UNiagaraStackFunctionInput* Input : ModuleInputs)
		{
			if (Input->GetInputParameterHandle().GetName() == FName("Loop Behavior") && *(int32*)Input->GetLocalValueStruct()->GetStructMemory() == 0)
			{
				FNiagaraValidationResult Result(ENiagaraValidationSeverity::Warning, LOCTEXT("NoInfiniteParticlesSummary", "check loop behavior"), LOCTEXT("NoInfiniteParticlesDescription", "paricles reaching lifetime not killed in ParticleState"), Input);
				Results.Add(Result);
				break;
			}
		}
	}
}

然后把这个规则加到ParticleState Module里, 这样参数设置错误的时候就可以报警:

[Image Removed]

[Attachment Removed]