※この記事で使用しているUnrealのVersionは04.26.0です。

※この記事のサンプルプロジェクトは以下URLにアップされています。

サンプルプロジェクト

昨今のバージョンアップで、新規追加機能も豊富に増えていますが、既存の機能がさらに強化されるようなことも多くなりました。

今回は、バージョンアップされて最初若干どう使うかわからなかった、MaterialのCustomノードの使い方を軽くですがメモ程度に紹介します。

MaterialのCustomノードを知らない方もいるかと思いますので、
その際は以下の記事をまずはご覧ください(先人たちがいっぱい深淵を除いてくれています)

公式ドキュメント:

Custom 表現式

Customノード説明系:

マテリアルエディタのCustomノードあれこれ

UE4のCustomノード(カスタムHLSLシェーダ)を使ってみた

以下は上記記事を一通り把握した前提での解説となります。

新しくなったMaterialのCustomノード レベル【★★★】

Customノードをマテリアルエディターで作成すると、デフォルトでこんな感じのものが作られます。

では、Detailのプロパティを見ていきましょう。

灰色の部分は前々からあったプロパティなので説明は省略します。

赤い部分は4.26から追加されたプロパティになります。
また、オレンジの部分は4.25から追加されたプロパティになります。

今回はこの色付きの部分の説明をいたします。

①Additional Outputs

4.26から登場したこのプロパティ。
個人的には「ようやく来た!」と言うような歓喜が素で漏れてしまったアップデートです。

機能としましては、単純に出力できるパラメータの数を増やせるだけです。

この配列に要素を追加すると、出力するピンの名前を入力するプロパティが現れます。
このプロパティに「None」以外の文字を入れると、出力ピンが増え入力した名前がそのピンにつきます。

また、既存の出力ピンには「return」という文字が明示されます。

そして、既存の出力ピンと同じように、出力する型を設定できます。

では、この追加で定義した出力ピンに値を渡したい場合はどのようにすればよいのでしょうか?

答えは簡単で、出力ピンに定義したものは自動で変数に昇格されているため、変数定義をせずにそのまま変数として扱います。

例えば、TestOutput1に値を入れる場合

TestOutput1 = float3(0,0,1);
return 0.0;

とCustomノードのコードを記載してあげると、TestOutput1の値がfloat3(0,0,1)として出力されます。

ちなみに、コンパイルされて自動生成されたHLSLコードの中身を見てみます。

//省略
MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters, inout MaterialFloat3 TestOutput1, inout MaterialFloat3 TestOutput2)
{
TestOutput1 = float3(0,0,1);
return 0.0;
}
//……途中まで省略
    // Now the rest of the inputs
    MaterialFloat3 Local0 = lerp(MaterialFloat3(0.00000000,0.00000000,0.00000000),Material.VectorExpressions[1].rgb,MaterialFloat(Material.ScalarExpressions[0].x));
    MaterialFloat3 Local1 = MaterialFloat3(0.0f, 0.0f, 0.0f);
    MaterialFloat3 Local2 = MaterialFloat3(0.0f, 0.0f, 0.0f);
    MaterialFloat3 Local3 = CustomExpression0(Parameters,Local1,Local2);

    PixelMaterialInputs.EmissiveColor = Local0;
    PixelMaterialInputs.Opacity = 1.00000000;
    PixelMaterialInputs.OpacityMask = 1.00000000;
    PixelMaterialInputs.BaseColor = Local1;
    PixelMaterialInputs.Metallic = 0.00000000;
    PixelMaterialInputs.Specular = 0.50000000;
//以下省略

上記コードの中で「Local1」という変数に注目します。

このLocal1は、Customノードで定義した出力用の変数が自動で宣言されたものです。
この変数を「CustomExpression0」関数の引数に渡されています。

このタイミングで、このLocal1変数が参照渡しされ、CustomExpression0内で値が更新され、その結果をBaseColorに入力しているというわけです。

さて、次に「Additional Defines」です。

②Additional Defines

Additional Definesは特に説明することはなく、単に「#define」を行えるだけです。

Additional Definesの配列の要素を追加すると、「Define Name」と「Define Value」を入力するプロパティが現れます。

ここに任意のプロパティを入力することで、機能するようになります。

#if TEST_DEFINE
	return float3(1.0,0.0,0.0);
#else
	return float3(0.0,1.0,0.0);
#endif

TEST_DEFINE = 0の場合

TEST_DEFINE = 1の場合

Defineを宣言すると、自動生成されるHLSLのCustomExpression関数の宣言前に以下のような感じでdefineが追加されます。

// Uniform material expressions.
#ifndef TEST_DEFINE
#define TEST_DEFINE 1
#endif//TEST_DEFINE
MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
{
#if TEST_DEFINE
    return float3(1.0,0.0,0.0);
#else
    return float3(0.0,1.0,0.0);
#endif
}

今までは裏技的なやり方でしかできなかったことが正式にできるようになって嬉しいですね!
(裏技はこちら↓)

[UE4] Customノード3分ハッキング

最後に「Include File Paths」についてです。

③Include File Paths

これは、EngineやPlugin、またはProjectのShaderファイル(ushまたはusfファイル)を明示的にIncludeして使うことができます。

自作のシェーダーファイルを使いたい場合などは結構使えるかと思います。

プロジェクトに自作シェーダーを追加して使用するやり方は以下が参考になりました。

【UE4】USF(Unreal Shader File) をすぐに始める環境設定 Project編

C++での実装になりますが、この記事に添付したサンプルプロジェクトでは
[プロジェクト名].hと[プロジェクト名].cppのファイルに以下のように追記します。

KA_MatCustomNode.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FKA_MatCustomNode : public IModuleInterface
{
public:
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;

    
};

KA_MatCustomNode.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "KA_MatCustomNode.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_PRIMARY_GAME_MODULE(FKA_MatCustomNode, KA_MatCustomNode, "KA_MatCustomNode" );

void FKA_MatCustomNode::StartupModule()
{
    FString ShaderDirectory = FPaths::Combine(FPaths::ProjectDir(), TEXT("Shader"));
    if (!AllShaderSourceDirectoryMappings().Contains("/Project"))
    {
        AddShaderSourceDirectoryMapping("/Project", ShaderDirectory);
    }

}

void FKA_MatCustomNode::ShutdownModule()
{
}

また、build.csには「”RenderCore”」を追加しています。

KA_MatCustomNode.Build.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class KA_MatCustomNode : ModuleRules
{
	public KA_MatCustomNode(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "RenderCore" });

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

あとは、プロジェクトファイルがあるフォルダ内に「Shader」というフォルダを作成さえすれば、その中にある「ush or usf」ファイルを「/Project/」でのパス指定で使用できるようになります。

↓Shaderフォルダ作成

MyShader.usf作成

MyShader.usfの中身は以下のような感じです。(適当です)

const static float3 MyFloat = float3(1.0,0.0,0.0);

float3 MyFunction()
{
	return float3(0.0,1.0,0.0);
}

これをビルドしてマテリアルエディターでCustomノードで使用してみます。

Customノードのコード

return MyFloat;

Include File Pathsの中身

/Project/MyShader.usf

Customノードのコードを以下のように変更

return MyFunction();

このように、自分で定義したシェーダーファイルを扱うことができました!

以上のように、最近のバージョンアップでマテリアル内でやれることの幅が格段に広がってきており、それを簡単に作成できるようになりました!

ざっくりとした説明になって申し訳ありませんが、みなさんも是非一度新しくなったCustomノードを使ってみてください!

以上。

※この記事のサンプルプロジェクトは以下URLにアップされています。

サンプルプロジェクト

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です