C++ ときどき ごはん、わりとてぃーぶれいく☆

Wonder Rabbit Projectのなかのひとのブログ。主にC++。

UE4/C++: 4.18 -> 4.19 エンジンアップデートトラブル; `UMaterialInstance::GetVectorParameterValue` の仕様変更と "Material Layers"

現行プロジェクトに必要なプラグインの 4.19 対応も進んできたので、手元のプロジェクトを 4.18 から 4.19 へエンジンアップデートしてみました。エンジンの仕様変更によるトラブルがあったので対処方法と併せて紹介します。

4.18 -> 4.19 における UMaterialInstance::GetVectorParameterValue の仕様変更

UMaterialInstance::GetVectorParameterValue の引数仕様が後方互換性なしで変更されていました。

Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h:

// 4.18
virtual ENGINE_API bool GetVectorParameterValue(FName ParameterName, FLinearColor& OutValue) const override;
// 4.19
virtual ENGINE_API bool GetVectorParameterValue(const FMaterialParameterInfo& ParameterInfo, FLinearColor& OutValue, bool bOveriddenOnly = false) const override;
  1. 第一引数が変更: FName ParameterName -> const FMaterialParameterInfo& ParameterInfo
  2. 第三引数が追加: bool bOveriddenOnly = false

FMaterialParameterInfo は 4.18 には存在しない 4.19 で追加された型で MaterialInstance.h と同じ場所に追加された MaterialLayersFunctions.h で定義されていた。

Engine/Source/Runtime/Engine/Classes/Materials/MaterialLayersFunctions.h:

// 本来のソースからメンバー変数と ctor を引用、日本語で概説を付けた。
USTRUCT(BlueprintType)
struct ENGINE_API FMaterialParameterInfo
{ GENERATED_USTRUCT_BODY()
  
  // 最低限これだけ与えればよい。 4.18 まで直接与えていた FName のパラメーターに相当
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  FName Name;
  
  // グローバルパラメーターか、あるいはレイヤーパラメーターまたはブレンドパラメーターかを設定。 4.19 で追加。
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  TEnumAsByte<EMaterialParameterAssociation> Association;
  
  // グローバルパラメーターの場合は INDEX_NONE, レイヤーパラメーターまたはブレンドパラメーターの場合は有効なインデックス値を設定する。 4.19 で追加。
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParameterInfo)
  int32 Index;
  
  // ctor pattern 1
  FMaterialParameterInfo(const TCHAR* InName, EMaterialParameterAssociation InAssociation = EMaterialParameterAssociation::GlobalParameter, int32 InIndex = INDEX_NONE);
  // ctor pattern 2
  FMaterialParameterInfo(FName InName = FName(), EMaterialParameterAssociation InAssociation = EMaterialParameterAssociation::GlobalParameter, int32 InIndex = INDEX_NONE);
  
  // ほかは省略

4.18 まで FName ParameterName として直接扱っていたパラメーターは 4.19 では FMaterialParameterInfo::Name に放り込んで扱うようだ。 4.18 まで第一引数を明示的に FName 型で与えていなかった場合には 4.18 から 4.19 へプロジェクトのエンジンアップデートを行う場合にこの絡みを使っている C++ ソースコードがあれば手書きの対応が必要となる。 第三引数については省略すれば INDEX_NONE がデフォルトパラメーターからセットされるため、さしあたり気にする事はない。

// 4.18 までこんな具合にコードしていた場合は
material->GetVectorParameterValue( "my_vector_param", buffer );
// 4.19 では最低限こんな具合で第一引数を明示的に FName 型で与えるようにすればコンパイル可能になる
material->GetVectorParameterValue( FName( "my_vector_param" ), buffer );

おまけ1: EMaterialParameterAssociation

UENUM()
enum EMaterialParameterAssociation
{
  LayerParameter,
  BlendParameter,
  GlobalParameter,
};

おまけ2: グローバルパラメーター、レイヤーパラメーター、ブレンドパラメーターとは何か。どうしてこうなった?

UE4 では 4.19 の新機能として "Material Layers" を実装した。

従来は1つ1つのマテリアルの単位で、その中でテクスチャーサンプリングしてパラメーターを合成したりするだけだったが、 この新機能により「複数のマテリアル群からなるマテリアル(="Material Layers")」を直接的にまとめて扱えるようになった。

この新機能に対応するため、従来はマテリアルごとに 4.19 からグローバルパラメーターと明示的に呼び分けられるようになったマテリアル内のシンボル名のほか、 「レイヤーのインデックス何番目の」という情報が必要な "Material Layers" タイプのマテリアルへ従来のマテリアルと統合的に対応するため 単なる FName だけのパラメーターから FMaterialParameterInfo への拡張が行われた。

"Material Layers" 参考