Qiita Conference 2025

ymrl (@ymrl)

がんばらないアクセシビリティ: より幅広く価値を届けるために

0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[UE5]NiagaraのDecalでDynamicParameterを使えるようにする

Last updated at Posted at 2025-03-29

本記事ではNiagaraのDecalRendererでDynamicMaterialParametersモジュールを使用する方法を紹介します。
image.png

概要

リッチなNiagaraを作るにあたって、NiagaraからMaterialへ動的に値を伝播させるDynamicMaterialParameterモジュールは結構重要になります。
パラメータはfloat4 x4セット、合計16個しか渡せないとはいえ、あれば表現の幅は大きく変わるはず。

MeshRendererやSpriteRendererでは当然のように使われているDynamicMaterialParameterモジュールですが、現状(UE5.5)DecalRendererでは使用できません。
アーティストは泣く泣くDecalColor(float4)を分解して使うわけですね。

image.png

本記事ではDecalRendererでもDynamicMaterialParameterモジュールを使用できるようにする方法をまとめます。
エンジンソースの変更が含まれますので責任の取れるプログラマ向けです。

開発環境

UE5.2

実装

ソースの変更箇所はそこそこ多いですが、大体は既存のDecalColorの処理に則って追加しています。
独自に定義したDECAL_RENDERER_EXTENSIONで囲った部分が追加したコードです。

SceneManagement.h

ここでDeferredDecalの更新用パラメータを定義します。

SceneManagement.h
class FDeferredDecalProxy
{
    :
#if DECAL_RENDERER_EXTENSION
	uint32 DecalMaterialParamValidMask = 0x0000;
	FLinearColor DecalDynamicMaterialParameter0 = FLinearColor::Black;
	FLinearColor DecalDynamicMaterialParameter1 = FLinearColor::Black;
	FLinearColor DecalDynamicMaterialParameter2 = FLinearColor::Black;
	FLinearColor DecalDynamicMaterialParameter3 = FLinearColor::Black;
#endif // DECAL_RENDERER_EXTENSION
    :
};
:
struct FDeferredDecalUpdateParams
{
    :
#if DECAL_RENDERER_EXTENSION
	uint32					MaterialParamValidMask = 0x0000;
	FLinearColor			DynamicMaterialParameter0 = FLinearColor::Black;
	FLinearColor			DynamicMaterialParameter1 = FLinearColor::Black;
	FLinearColor			DynamicMaterialParameter2 = FLinearColor::Black;
	FLinearColor			DynamicMaterialParameter3 = FLinearColor::Black;
#endif // DECAL_RENDERER_EXTENSION
    :
};

RenderScene.cpp

ここではシェーダー側で参照する値を更新しています。

RenderScene.cpp
void FScene::BatchUpdateDecals(TArray<FDeferredDecalUpdateParams>&& UpdateParams)
{
    ENQUEUE_RENDER_COMMAND(FBatchUpdateDecalsCommand)(
		[Scene=this, UpdateParams_RT=MoveTemp(UpdateParams)] (FRHICommandListBase&)
		{
			for (const FDeferredDecalUpdateParams& DecalUpdate : UpdateParams_RT )
			{
                :
#if DECAL_RENDERER_EXTENSION
				DecalUpdate.DecalProxy->DecalMaterialParamValidMask = DecalUpdate.MaterialParamValidMask;
				DecalUpdate.DecalProxy->DecalDynamicMaterialParameter0 = DecalUpdate.DynamicMaterialParameter0;
				DecalUpdate.DecalProxy->DecalDynamicMaterialParameter1 = DecalUpdate.DynamicMaterialParameter1;
				DecalUpdate.DecalProxy->DecalDynamicMaterialParameter2 = DecalUpdate.DynamicMaterialParameter2;
				DecalUpdate.DecalProxy->DecalDynamicMaterialParameter3 = DecalUpdate.DynamicMaterialParameter3;
#endif // DECAL_RENDERER_EXTENSION
    :
}

NiagaraDecalRendererProperties.h/.cpp

ここではNiagaraのDecalRendererにBindingを追加する処理と、DynamicMaterialParameterモジュールのValueと有効/無効切り替えMaskの更新を追加しています。
image.png

image.png

NiagaraDecalRendererProperties.h
class UNiagaraDecalRendererProperties : public UNiagaraRendererProperties
{
public:
    :
#if DECAL_RENDERER_EXTENSION
    // ここでNiagaraのDecalRendererにBindingを追加..
	UPROPERTY(EditAnywhere, Category = "Bindings")
	FNiagaraVariableAttributeBinding DynamicMaterialBinding;
	UPROPERTY(EditAnywhere, Category = "Bindings")
	FNiagaraVariableAttributeBinding DynamicMaterialBinding1;
	UPROPERTY(EditAnywhere, Category = "Bindings")
	FNiagaraVariableAttributeBinding DynamicMaterialBinding2;
	UPROPERTY(EditAnywhere, Category = "Bindings")
	FNiagaraVariableAttributeBinding DynamicMaterialBinding3;

    // BindingへのAccessorを追加.
	UPROPERTY()
	uint32 MaterialParamValidMask = 0;
	FNiagaraDataSetAccessor<FVector4f>			MaterialParam0DataSetAccessor;
	FNiagaraDataSetAccessor<FVector4f>			MaterialParam1DataSetAccessor;
	FNiagaraDataSetAccessor<FVector4f>			MaterialParam2DataSetAccessor;
	FNiagaraDataSetAccessor<FVector4f>			MaterialParam3DataSetAccessor;
#endif // DECAL_RENDERER_EXTENSION
};
NiagaraDecalRendererProperties.cpp
namespace NiagaraDecalRendererPropertiesLocal
{
    :
	static void SetupBindings(UNiagaraDecalRendererProperties* Props)
	{
        :
#if DECAL_RENDERER_EXTENSION
		Props->DynamicMaterialBinding = FNiagaraConstants::GetAttributeDefaultBinding(SYS_PARAM_PARTICLES_DYNAMIC_MATERIAL_PARAM);
		Props->DynamicMaterialBinding1 = FNiagaraConstants::GetAttributeDefaultBinding(SYS_PARAM_PARTICLES_DYNAMIC_MATERIAL_PARAM_1);
		Props->DynamicMaterialBinding2 = FNiagaraConstants::GetAttributeDefaultBinding(SYS_PARAM_PARTICLES_DYNAMIC_MATERIAL_PARAM_2);
		Props->DynamicMaterialBinding3 = FNiagaraConstants::GetAttributeDefaultBinding(SYS_PARAM_PARTICLES_DYNAMIC_MATERIAL_PARAM_3);
#endif // DECAL_RENDERER_EXTENSION
    :
    }
}
    
UNiagaraDecalRendererProperties::UNiagaraDecalRendererProperties()
{
	AttributeBindings =
	{
        :
#if DECAL_RENDERER_EXTENSION
		&DynamicMaterialBinding,
		&DynamicMaterialBinding1,
		&DynamicMaterialBinding2,
		&DynamicMaterialBinding3,
#endif // DECAL_RENDERER_EXTENSION
        :
    }
    :
}

void UNiagaraDecalRendererProperties::CacheFromCompiledData(const FNiagaraDataSetCompiledData* CompiledData)
{
    :
#if DECAL_RENDERER_EXTENSION
	InitParticleDataSetAccessor(MaterialParam0DataSetAccessor, CompiledData, DynamicMaterialBinding);
	InitParticleDataSetAccessor(MaterialParam1DataSetAccessor, CompiledData, DynamicMaterialBinding1);
	InitParticleDataSetAccessor(MaterialParam2DataSetAccessor, CompiledData, DynamicMaterialBinding2);
	InitParticleDataSetAccessor(MaterialParam3DataSetAccessor, CompiledData, DynamicMaterialBinding3);

#if WITH_EDITORONLY_DATA	
	auto FindNameInCompiledData = [&](FName BindingName)
	{
		int32 Index = CompiledData->Variables.IndexOfByPredicate(
		[&](const FNiagaraVariable& InVariable)
			{
				return InVariable.GetName() == BindingName;
			}
		);
		return Index != INDEX_NONE ? BindingName : NAME_None;
	};
	
	MaterialParamValidMask = GetDynamicParameterCombinedChannelMask(
		FindNameInCompiledData(DynamicMaterialBinding.GetDataSetBindableVariable().GetName()),
		FindNameInCompiledData(DynamicMaterialBinding1.GetDataSetBindableVariable().GetName()),
		FindNameInCompiledData(DynamicMaterialBinding2.GetDataSetBindableVariable().GetName()),
		FindNameInCompiledData(DynamicMaterialBinding3.GetDataSetBindableVariable().GetName())
	);
#endif // WITH_EDITORONLY_DATA
#endif // DECAL_RENDERER_EXTENSION

DecalRenderingShared.h/.cpp

DecalRenderingShared.h
struct FTransientDecalRenderData
{
    :
#if DECAL_RENDERER_EXTENSION
	uint32 MaterialParamValidMask;
	FLinearColor DynamicParameter;
	FLinearColor DynamicParameter1;
	FLinearColor DynamicParameter2;
	FLinearColor DynamicParameter3;
#endif // DECAL_RENDERER_EXTENSION
    :
};
DecalRenderingShared.cpp
FTransientDecalRenderData::FTransientDecalRenderData(const FDeferredDecalProxy& InDecalProxy, float InConservativeRadius, float InFadeAlpha, EShaderPlatform ShaderPlatform, ERHIFeatureLevel::Type FeatureLevel)
    :
#if DECAL_RENDERER_EXTENSION
	, MaterialParamValidMask(InDecalProxy.DecalMaterialParamValidMask)
	, DynamicParameter(InDecalProxy.DecalDynamicMaterialParameter0)
	, DynamicParameter1(InDecalProxy.DecalDynamicMaterialParameter1)
	, DynamicParameter2(InDecalProxy.DecalDynamicMaterialParameter2)
	, DynamicParameter3(InDecalProxy.DecalDynamicMaterialParameter3)
#endif // DECAL_RENDERER_EXTENSION
    :
:

class FDeferredDecalPS : public FMaterialShader
{
    :
    FDeferredDecalPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FMaterialShader(Initializer)
	{
        :
#if DECAL_RENDERER_EXTENSION
		MaterialParamValidMask.Bind(Initializer.ParameterMap, TEXT("MaterialParamValidMask"));
		DynamicParameter.Bind(Initializer.ParameterMap, TEXT("DynamicParameter"));
		DynamicParameter1.Bind(Initializer.ParameterMap, TEXT("DynamicParameter1"));
		DynamicParameter2.Bind(Initializer.ParameterMap, TEXT("DynamicParameter2"));
		DynamicParameter3.Bind(Initializer.ParameterMap, TEXT("DynamicParameter3"));
#endif // DECAL_RENDERER_EXTENSION
        :
    }
    :
    void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FViewInfo& View, const FDeferredDecalProxy& DecalProxy, const FMaterialRenderProxy* MaterialProxy, const FMaterial* MaterialResource, const float FadeAlphaValue = 1.0f, const FScene* Scene = nullptr)
	{
        :
#if DECAL_RENDERER_EXTENSION
		SetShaderValue(BatchedParameters, MaterialParamValidMask, DecalProxy.DecalMaterialParamValidMask);
		SetShaderValue(BatchedParameters, DynamicParameter, DecalProxy.DecalDynamicMaterialParameter0);
		SetShaderValue(BatchedParameters, DynamicParameter1, DecalProxy.DecalDynamicMaterialParameter1);
		SetShaderValue(BatchedParameters, DynamicParameter2, DecalProxy.DecalDynamicMaterialParameter2);
		SetShaderValue(BatchedParameters, DynamicParameter3, DecalProxy.DecalDynamicMaterialParameter3);
#endif // DECAL_RENDERER_EXTENSION
        :
    }

    :
	LAYOUT_FIELD(FShaderParameter, DecalParams);
	LAYOUT_FIELD(FShaderParameter, DecalColorParam);
#if DECAL_RENDERER_EXTENSION
	LAYOUT_FIELD(FShaderParameter, MaterialParamValidMask);
	LAYOUT_FIELD(FShaderParameter, DynamicParameter);
	LAYOUT_FIELD(FShaderParameter, DynamicParameter1);
	LAYOUT_FIELD(FShaderParameter, DynamicParameter2);
	LAYOUT_FIELD(FShaderParameter, DynamicParameter3);
#endif // DECAL_RENDERER_EXTENSION
    :
};

NiagaraRendererDecals.cpp

ここではPropertiesで追加したBindingの値をFDeferredDecalUpdateParamsに設定しています。
大体DecalColorの処理と同様なので細かい部分は割愛します。

NiagaraRendererDecals.cpp
FNiagaraDynamicDataBase* FNiagaraRendererDecals::GenerateDynamicData(const FNiagaraSceneProxy* Proxy, const UNiagaraRendererProperties* InProperties, const FNiagaraEmitterInstance* Emitter) const
{
    :
#if DECAL_RENDERER_EXTENSION
	const FLinearColor LocalDefaultDynamicMaterialParameter0 = ParameterStore.GetParameterValueOrDefault(RendererProperties->DynamicMaterialBinding.GetParamMapBindableVariable(), FLinearColor::Black);
	const FLinearColor LocalDefaultDynamicMaterialParameter1 = ParameterStore.GetParameterValueOrDefault(RendererProperties->DynamicMaterialBinding1.GetParamMapBindableVariable(), FLinearColor::Black);
	const FLinearColor LocalDefaultDynamicMaterialParameter2 = ParameterStore.GetParameterValueOrDefault(RendererProperties->DynamicMaterialBinding2.GetParamMapBindableVariable(), FLinearColor::Black);
	const FLinearColor LocalDefaultDynamicMaterialParameter3 = ParameterStore.GetParameterValueOrDefault(RendererProperties->DynamicMaterialBinding3.GetParamMapBindableVariable(), FLinearColor::Black);
#endif // DECAL_RENDERER_EXTENSION
    :
	if (RendererProperties->SourceMode == ENiagaraRendererSourceDataMode::Particles)
	{
        :
#if DECAL_RENDERER_EXTENSION
		const auto DynamicParameterReader = RendererProperties->MaterialParam0DataSetAccessor.GetReader(DataSet);
		const auto DynamicParameterReader1 = RendererProperties->MaterialParam1DataSetAccessor.GetReader(DataSet);
		const auto DynamicParameterReader2 = RendererProperties->MaterialParam2DataSetAccessor.GetReader(DataSet);
		const auto DynamicParameterReader3 = RendererProperties->MaterialParam3DataSetAccessor.GetReader(DataSet);
#endif // DECAL_RENDERER_EXTENSION
        :
		for (uint32 ParticleIndex = 0; ParticleIndex < DataToRender->GetNumInstances(); ++ParticleIndex)
		{
            :
#if DECAL_RENDERER_EXTENSION
			UpdateParams.DynamicMaterialParameter0 = DynamicMaterialParameter0;
			UpdateParams.DynamicMaterialParameter1 = DynamicMaterialParameter1;
			UpdateParams.DynamicMaterialParameter2 = DynamicMaterialParameter2;
			UpdateParams.DynamicMaterialParameter3 = DynamicMaterialParameter3;
#endif // DECAL_RENDERER_EXTENSION
        }
    }
    :
}

DeferredDecal.usf

ついにシェーダーコードです。でも大したことはしていません。
パラメータを追加して、Niagaraで使用するMaterialParameter.Particleに設定しているだけです。
ここで定義したパラメータ名はDecalRenderingShared.h/cppで指定します。

DeferredDecal.usf
:
// Decal color can be accessed using the material node
float4 DecalColorParam;

#if DECAL_RENDERER_EXTENSION
uint MaterialParamValidMask;
float4 DynamicParameter;
float4 DynamicParameter1;
float4 DynamicParameter2;
float4 DynamicParameter3;
#endif // DECAL_RENDERER_EXTENSION
:
void FPixelShaderInOut_MainPS(inout FPixelShaderIn In, inout FPixelShaderOut Out, uint ArrayIndex)
{
    :
#if DECAL_RENDERER_EXTENSION
#if (DYNAMIC_PARAMETERS_MASK != 0)
	MaterialParameters.Particle.DynamicParameterValidMask = MaterialParamValidMask;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
	MaterialParameters.Particle.DynamicParameter = DynamicParameter;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
	MaterialParameters.Particle.DynamicParameter1 = DynamicParameter1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
	MaterialParameters.Particle.DynamicParameter2 = DynamicParameter2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
	MaterialParameters.Particle.DynamicParameter3 = DynamicParameter3;
#endif
#endif // DECAL_RENDERER_EXTENSION
    :
}

MaterialTemplate.ush

ここではDynamicParameterを使用する条件を変更しています。
デフォルトではFNiagaraVertexFactoryBaseを継承したクラスで有効にされるフラグをみる条件になっていますが、Decalは既存のDeferredDecalの処理を使用している関係でVertexFactoryは使用していません。
そのため条件になっているVertexFactory関連のフラグをコメントアウトしたり、DecalRendererで有効になるフラグを使用するようにしています。

MaterialTemplate.ush
:
struct FMaterialParticleParameters
{
    :
// #if DECAL_RENDERER_EXTENSION ifプリプロセッサを挟むためコメントアウト.
// 追加コード.
#if DYNAMIC_PARAMETERS_MASK != 0
// 元コード.
//#if NIAGARA_PARTICLE_FACTORY && (DYNAMIC_PARAMETERS_MASK != 0)
	uint DynamicParameterValidMask;
// #endif // DECAL_RENDERER_EXTENSION
    :
};
:
float4 GetDynamicParameter(FMaterialParticleParameters Parameters, float4 Default, int ParameterIndex=0)
{
// #if DECAL_RENDERER_EXTENSION ifプリプロセッサを挟むためコメントアウト.
// 追加コード.
#if NIAGARA_PARTICLE_FACTORY || (DECAL_PRIMITIVE)
// 元コード.
//#if (NIAGARA_PARTICLE_FACTORY)
// #endif // DECAL_RENDERER_EXTENSION

変更箇所多すぎィ!

結果

DynamicParameterのRGBをベースカラー、Aをオパシティとして使用するシンプルなDeferredDecalマテリアルを用意しました。
image.png

DynamicParameterのデフォルト値は[1.0, 0.0, 0.0, 0.5]にしてあるので、マテリアルを直接レベルに配置すると半透明の赤いDecalが出ます。
image.png

このマテリアルをNiagaraのDecalRendererに設定します。
image.png

サイズが違うのはNiagara側でDecalSizeを設定しているからです。
image.png

DynamicParameterModuleを追加して任意の値を設定します。
今回は[0.0, 0.0, 1.0, 1.0]としました。
image.png

NiagaraのDynamicParameterModuleの値が反映されましたね。
image.png

まとめ

DecalRendererでもDynamicParameterが使用できるようになりました。
これでDecalエフェクトの表現の幅が広がりますね。

変更箇所が多いので運用・保守にはご注意ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Qiita Conference 2025 will be held!: 4/23(wed) - 4/25(Fri)

Qiita Conference is the largest tech conference in Qiita!

Keynote Speaker

ymrl、Masanobu Naruse, Takeshi Kano, Junichi Ito, uhyo, Hiroshi Tokumaru, MinoDriven, Minorun, Hiroyuki Sakuraba, tenntenn, drken, konifar

View event details
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?