PaperSloth’s diary

主にゲーム開発関連についての記事を書きます。

UE4 個人開発メモ

最終更新日:2017/12/03

概要

 個人開発でのUE4のEditor Preference, Project Settings等のメモ
 随時更新していきます。
 基本はWindowsPC向けの内容。
 家庭用ゲーム機、アーケードゲーム、モバイル、XR(AR / VR)でも役立つ内容も含みます。
 各項目には確認時のバージョンを記載しています。
 バージョンが古かったり新しかったりすると
 項目がなくなったり、場所や名前が変わったりしている可能性があります。

環境

・Platform : Windows
・Unreal Engine4.17.2~
Visual Studio Community 2015


Project Settings

Windowタイトルの変更方法(UE4.17.2)

 WindowタイトルとはPC向けに作成した際のWidnowの左上に出るタイトルです。
f:id:PaperSloth:20171130003303p:plain

 何も指定していない場合はProject名が表示されます。

 設定は下図のProject - Description - Displayed
 「Project Displayed Title」から変更できます。
f:id:PaperSloth:20171130004532p:plain

 試しに"Example Window Name"と入れてみました。
f:id:PaperSloth:20171130004635p:plain

Application名の変更方法(UE4.17.2)

 上記Windowsタイトルとよく間違えやすいのがこれです。
 設定は下図のProject - Description - About
 「Project Name」から変更できます。
 デフォルトではUE4Gameと入っています。
f:id:PaperSloth:20171130005438p:plain

 よくWindowタイトルを変更しようとしますが、ここを変えても上手くいきません。
 この名前はタスクマネージャー等で表示されるアプリの名前です。
f:id:PaperSloth:20171130005618p:plain

 ちょっと図がわかりにくいのですがProject Nameがあって、その下にWindowTitleがくるようになっています。
 編集をしていない場合だと、UE4Gameの下にProject名がくるようになっています。
f:id:PaperSloth:20171130010129p:plain

シェーダーモデルの制限によるメモリ容量削減(UE4.17.2)

 設定は下図のPlatforms - Windows
 「Targeted RHIs」から変更できます。

 UE4Windows向けに作成している場合
 デフォルトのRHI(Rendering Hardward Interface)はDX10, DX11が有効になっています。
f:id:PaperSloth:20171130220108p:plain
 これをDX11(ShaderModel5)のみにすることで不要なシェーダーが減り、パッケージ容量を削減できます。
 ThirdPersonTemplate等で試してみてもほぼ全く変わらないのですが
 規模が大きく、マテリアルが増えるほど効果が現れやすい部分です。

 試しに自分のゲームで比較してみた結果
 DX10, 11だと242KBのシェーダー
f:id:PaperSloth:20171130221048p:plain
 DX11のみだと124KBと約半分の容量になりました。
f:id:PaperSloth:20171130221057p:plain

 このように数百KB程度だと微々たる差ですが、これが数百、数千のマテリアルとなると話が変わってきます。
 また、シェーダーも1つで数百MBだと半分ほどの容量になるのは大きな変化ですね。

パッケージング関連

 項目が多いので、細かく分けます。
 設定箇所はProject - Packaging以下のものになります。

PakFileの使用(UE4.17.2)

 「Use Pak File」にチェックを入れると有効になります。
 説明の前に図で見てもらうと分かりやすいと思います。
 Pak Fileを使用した場合
f:id:PaperSloth:20171130222234p:plain
 中には.pakの形式でContent以下のAssetが1つのデータに圧縮されています。

 Pak Fileを使用しない場合
f:id:PaperSloth:20171130222333p:plain

 Pakファイルの使用は容量の削減になり
 転送ファイル数が減るので配布時のダウンロードも早くなり
 ロードも早くなるため使用することを推奨します。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :532MB
 使用しない場合 :786MB

パッケージの圧縮(4.17.2)

 「Create compressed cooked packages」にチェックを入れると有効になります。
 f:id:PaperSloth:20171203220605p:plain
 なお、このオプションの効果を有効にするにはUse Pak Fileにチェックを入れておく必要があります。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :547MB
 使用しない場合 :950MB

 さて、パッケージの圧縮はDLで配信するPC向け等にはオススメですが、
 一部プラットフォームは注意が必要です。
 PlayStation 4の場合
  PlayStation 4 の圧縮と重複し、ファイル サイズは減らずにロード時間が長くなってしまいます。
 Nintendo Switchの場合
  ロード時間が早くなる場合と遅くなる場合があります。
 詳しくは下部の参考資料のリンクを見てください。


Editor Preference

Blutilityの有効化(UE4.17.2)

 BlutilitはBlueprintをEditor上で呼び出すことでお手軽にEditor拡張が出来る機能です。
 UE4.17.2現在は実験的な機能として提供されています。
 この機能に関しては不安定というよりは、機能がまだ足りないため実験的な機能なのだと思います。

 設定は下図のEditor Preference - General - Experimental - Tools
 「Editor Utility Blueprints(Blutility)」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130011354p:plain

EQS(Environment Querying System)の有効化(UE4.17.2)

 EQSはAIが目的に応じた位置を探す時に使われる機能です。
 この位置は動的に生成され、その中から最もスコアの高い位置を選択します。

 こちらも実験的な機能として提供されていますが
 EpicGamesの開発タイトルである「Robo Recall」でも採用されており、信頼性は高いです。

 設定は下図のEditor Preference - General - Experimental - AI
 「Environment Querying System」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130012353p:plain

参考資料

シェーダーモデルの制限によるメモリ容量削減
バイキング様のスライド63ページ付近に該当箇所の説明があります。
マジシャンズデッド ポストモーテム ~マテリアル編~ (株式会社Byking: 鈴木孝司様、成相真治様) #UE4DD

パッケージング関連
パッケージの圧縮によるプラットフォームごとの注意点等詳しくはドキュメントに載っています。
Unreal Engine | プロジェクトのパッケージ化

UE4 Editorの言語設定を一時的に変える方法

環境

UE4.25.1

言語設定を一時的に変える方法

普段UE4を英語環境で使用しているけれど、他の人にEditorで説明する場合等に一時的に日本語環境に変えたいというケースがあります。

そういった時にUE4ではコンソールコマンドから変更することが可能です。
ただし、この機能は一時的なものでEditorを再起動した時には元に戻ります。
また、全てが正しく変更されるわけではないため、ブログやスライド作成時には後述の永続的に変える方法から変更してEditorを再起動することをオススメします。

変更方法は簡単で実行中またはOutput Logから
"culture=(言語)"です。
日本語に変更したい場合は"culture=ja"
英語にしたい場合は"culture=en"
実行時のコンソールコマンド入力は以下のどちらからでもよいです。
f:id:PaperSloth:20200621213537p:plain
f:id:PaperSloth:20200621213638p:plain

以下のようにOutput Logから入力した場合でも問題ありません。
f:id:PaperSloth:20200621213734p:plain

このコマンドで使うことはないかと思いますが、ConstrunctionScriptやBeginPlay等でも動作します。
f:id:PaperSloth:20200621213840p:plain

言語切り替えは他の多くの言語にも対応していますが、よく使うのは上記だと思いますので、他の言語は割愛させていただきます。

言語設定を永続的に変える方法

こちらは多くの情報が出てくると思いますが、一応紹介しておきます。
Editor Preferences(エディタの環境設定)から変更可能です。

General - Ragion & LanguageからEditor Languageを変更することで変更されます。
この方法で変更した場合はEditorを終了しても適用されます。
念のためEditorの再起動をしておくと部分的に言語が変わる恐れもなくて安心です。
f:id:PaperSloth:20200621214153p:plain

日本語の場合は一般 - 地域 & 言語のエディタの言語から変更可能です。
f:id:PaperSloth:20200621214424p:plain

UE4 LockOnCursorの実装

環境

UE4.25.1

概要

UE4でのロックオンの記事はちらほら見かけるけど、ロックオンカーソルの記事は少ないというのを見て書き始めました。
本記事ではロックオンする対象は1体を想定しています。
マルチロックオンでの運用も可能ですが、Widgetの場合は少し工夫が必要になります。

ロックオンの処理自体は事前に組まれていることを想定しています。
良いサンプルとは言えませんが、とりあえずのロックオンのサンプルとして下記を利用していただいても良いかと思います(このサンプルにはロックオンカーソルのロジックは実装されておりません)
github.com


完成イメージは以下のようになります。
f:id:PaperSloth:20200619223101p:plain


※実装に使用している「LockOnTarget」という変数がありますが
これはActor型の変数でPlayerやLockOn用のComponent等
ロックオン処理を行っているBlueprintから事前にHUD/Widgetに渡されている上での実装になります。
f:id:PaperSloth:20200620145352p:plain

一例としてPlayer側でロックオン処理を組んでいる場合のものを載せておきます。
PlayerRef : プレイヤーBlueprintへの参照
IsLockOn : プレイヤーがロックオン状態か判定するためのフラグ
LockOnTarget : ロックオン対象となるActor(必ず対象がいるとは限らないため、IsValidチェック)
f:id:PaperSloth:20200620145535p:plain

ロックオンカーソル実装(HUD編)

先ずはHUDでの実装についてです。
個人的にはWidgetでの実装をオススメしますが、こちらも紹介しておきます。

下図のようにHUD Blueprint内で処理を組むことでロックオンカーソルを表示できます。
f:id:PaperSloth:20200619211120p:plain

ここで注目すべきは「Project」ノードです。
「Project」ノードでロックオン対象の3次元座標を画面の2次元座標に変換してくれます。
あとはその位置データを元にDraw TextureやDraw Materialでロックオンカーソルを描画するだけです。

注意点として、このノードはHUD内でしか使えず「Event Receive Draw HUD」の中でしか機能しません。
そのため、Tick等で同じノードを組んだ場合には動作しません。

ロックオンカーソル実装(Widget編)

続いてWidgetでの実装です。
Widget内のDesignerでは図のようにCanvasPanelとImageだけのものを用意します。
f:id:PaperSloth:20200619220738p:plain

この時にLockOnCursorのVisibilityを「Hidden」か「Collapsed」にしておきます。
表示されてほしいのはロックオン中のみですので、デフォルトでは非表示でよいです。
f:id:PaperSloth:20200619220906p:plain


あとは図のようにBlueprintを組めば完成です。
f:id:PaperSloth:20200619221524p:plain

ロックオン対象が存在する時は表示して座標を更新し、いない時は非表示に切り替えています。
HUDではProjectを使用して2次元座標に変換していましたが
ProjectはHUD専用ですので、こちらではPlayerControllerの「Project World to Screen」を使用します。

この辺りの処理は何度か使うようであれば、関数ライブラリ等にまとめてしまってもよいかもしれませんね。
f:id:PaperSloth:20200619222328p:plain
f:id:PaperSloth:20200619222357p:plain

ロックオン処理の実装にもよりますが、開始/終了判定が取れる場合は以下のようによりシンプルにまとまると思います。
f:id:PaperSloth:20200619222708p:plain

まとめ

個人的にはWidgetでの実装をオススメしますが

とHUD編で書いたのですが、この理由についていくつか解説します
1. ロックオン開始時のアニメーションを追加できる
 ロックオンした時のカーソルの回転や拡縮や色替えなど各種アニメーションをWidgetで組んで実装することができます。
 HUDでも出来るかもしれませんが、結構な手間なので避けたいところです。
 ロックオン開始時ではなく、常時回転などを行いたい場合は以下のようにMaterialで組めばよいです
 papersloth.hatenablog.com

2. 画面サイズの変更に強い
 HUD版の現実装では画面解像度等を変えた時にロックオンカーソルも大きさが変わってしまいます。
 これでちょうど良いサイズになってくれると良いのですが、少し処理を加えて調整してやる必要があります。
 Widget版ではViewportScaleを考慮して計算しているため、表示 / 非表示の切り替えくらいで特に何も手を加える必要がない想定です。

HUDでの利点もないわけではないです。
マルチロックオンを行いたい場合は比較的処理が楽です。
Draw Texture/Materialが同時にロックオンした数と同じだけ描画されることにだけだからです。
例で渡したLockOnTargetを配列にしてループを回すだけで済みます。
f:id:PaperSloth:20200619211913p:plain

同じことをWidget版でやりたい場合は少し手間です。
図のようにLockOnCursorだけのWidgetを作成しておき
f:id:PaperSloth:20200619215814p:plain

ロックオン開始時にメインのWidgetのPanelにAdd Childして終了時にRemove Childする等でしょうか。
f:id:PaperSloth:20200619220053p:plain


ロックオンカーソルについては以上になります。

UE4 MaterialでTextureを回転させる

環境

UE4.25.1

CustomRotatorを使用する

Engine Content内のMaterial FunctionにCustomRotatorというものがあります。

これを使うだけでTextureの回転が可能です。
f:id:PaperSloth:20200615001731p:plain

引数について
・UVs : UVを渡す
・Rotation Center : 回転の中心位置
・Rotation Angle : 0-1で回転量を渡す 0.5 -> 180°, 1.0 -> 360°

使い方は簡単で180°回転させたい場合は以下のように繋ぐだけです。
上の画像が元画像で下が180°回転させたものです。
f:id:PaperSloth:20200615002338p:plain


ただし、このテクスチャをそのまま回転させるとテクスチャの繰り返し部分が見えておかしな表示になっていしまいます。
f:id:PaperSloth:20200615002836g:plain

これを修正するにはImportしたTextureを開いて
X/Y-axis Tiling MethodをWrapから「Clamp」に変更することで防げます
f:id:PaperSloth:20200615003003p:plain
f:id:PaperSloth:20200615003153g:plain

Textureを回転させる方法

Material内で回転させるためにはRotation Angleに「Time -> Frac」を渡すだけでよいです
f:id:PaperSloth:20200615003412p:plain

これはTimeの小数点部分だけを渡しているのですが
何をしているのかを見ていきましょう

先ずは以下のようにTime -> Fracした値を「DebugScalarValues」に繋ぎます。
f:id:PaperSloth:20200615004309p:plain

続いて「DebugScalarValues」ノードの上で右クリックして「Start Previewing Node」を選択します
f:id:PaperSloth:20200615003654p:plain

すると以下のように小数点部分が0から0.9999999までカウントされていることがわかります。
こうすることでRotation Angleの0-1の範囲に収まった上で回転させることができます
f:id:PaperSloth:20200615003803g:plain

最後にMaterial Instance側で調整しやすいように「ScalarParameter」を追加し、「RotationSpeed」としておきました
f:id:PaperSloth:20200615004455p:plain

これを応用することで以下のようなクルクル回転するロックオンカーソル等が作成できます
f:id:PaperSloth:20200615001622g:plain

Unity serializeについてのまとめ

目次

環境

Unity 2019.3.13f1

概要

組み込み型、Property、struct/classの Inspectorへの公開方法をまとめた記事になります

Unityのシリアル化については下記のドキュメントに記載があります
スクリプトのシリアル化 - Unity マニュアル

C#の型情報についてのドキュメントはこちら
型 - C# プログラミング ガイド | Microsoft Docs

[SerializeFiled]について

主に変数をInspectorに公開するために使用することが多いです

public class ExampleBehaviour : MonoBehaviour
{
    // 書き方は2通りあり、改行してもしなくてもよい
    [SerializeField]
    int ExampleValue = 10;

    [SerializeField] int Value = 10;
}

f:id:PaperSloth:20200525113603p:plain

public / private を書かなくてもよいのか、publicとの違い

先ずはpublic / privateを書かなくてもよいのかについてですが
C#のclassはアクセス修飾子がない場合に明示的にprivateになります
そのため以下の2つは同じ意味を持ちます

[SerializeField]
int ExampleValue = 10;
// どちらの書き方でも同じ意味をもつ
[SerializeField]
private int Value = 10;


次にpublicとの違いについて
public の場合[SerializeField]を付けなくてもInspectorに変数を公開できます
そこまでは同じです
ですが、アクセス修飾子が異なるので他のクラスから変更できてしまいます

[SerializeField]
int ExampleValue = 10;

public int Value = 10;

このクラス単体に限っては何の問題もありません
ただし、他のクラスから変更できてしまうため以下のような問題が発生します

先ずはExampleBehaviour にアクセスするためのクラスを用意します

public class TestBehaviour : MonoBehaviour
{
    [SerializeField]
    ExampleBehaviour Example;

    void Start()
    {
        Example.Value = 100;
    }
}

f:id:PaperSloth:20200525114818p:plain


実行するとInspector上で"10"だったExampleValueが"100"に上書きされてしまいます
f:id:PaperSloth:20200525114939p:plain

この書き方の場合には意図しない値の変更が行われる可能性があり
バグを生み出す原因となり得ます
Unityに限らずアクセス修飾子には気を付けましょう

PropertyをInspectorに公開する方法

Propertyは以下のようにSerializeFieldを付けてもInspectorに公開できません

[SerializeField]
int ExampleValue { get; set; }

f:id:PaperSloth:20200525120820p:plain

解決方法として[field: ] を付与することでInspectorに公開することができます

[field: SerializeField]
int ExampleValue { get; set; }

f:id:PaperSloth:20200525120905p:plain

backing field の表記になりパッと見では分かりにくくなってしまいます
(Propertyを公開していることを意図的に表現したい場合はこのままでよいですが)

解決策として以下のForumにある「RenameFieldAttribute」のようなclassを用意することで解決できます
https://forum.unity.com/threads/c-7-3-field-serializefield-support.573988/

public class ExampleBehaviour : MonoBehaviour
{
    [field: SerializeField]
    [field: RenameField(nameof(ExampleProperty))]
    int ExampleProperty { get; set; }

    [field: SerializeField]
    [field: RenameField("RenameValue")]
    int Value { get; set; }
}

f:id:PaperSloth:20200525121344p:plain

class, structをInspectorに公開する方法

classもstructもそのままではInspectorに公開することができません

using UnityEngine;

public class ExampleBehaviour : MonoBehaviour
{
    public struct StructData
    {
        public int Value;
        public string Name;
    }
    [SerializeField]
    StructData structData;

    public class ClassData
    {
        [SerializeField]
        string Tag;
    }
    [SerializeField]
    ClassData classData;
}

f:id:PaperSloth:20200525122809p:plain

どちらの場合でもInspectorに公開する場合は[System.Serializable] を使用することでInspectorに公開できます

using UnityEngine;

public class ExampleBehaviour : MonoBehaviour
{
    [System.Serializable]
    public struct StructData
    {
        public int Value;
        public string Name;
    }
    [SerializeField]
    StructData structData;

    [System.Serializable]
    public class ClassData
    {
        [SerializeField]
        string Tag;
    }
    [SerializeField]
    ClassData classData;
}

f:id:PaperSloth:20200525123019p:plain

まとめ

ここまでに紹介してきた書き方をざざっとまとめました。

using System;
using UnityEngine;

public class ExampleBehaviour : MonoBehaviour
{
    [SerializeField]
    int ExampleValue;
    [field: SerializeField]
    int PropertyValue { get; set; }
    // ※RenameFieldの拡張用のclassを記述した場合
    [field: SerializeField]
    [field: RenameField("RenameProperty")]
    int RenameValue { get; set; }

    // struct, class どちらの場合でも[System.Serializable]で対応可能
    // ここではusing System;を定義しているためSystemを省略
    [Serializable]
    public class ClassData
    {
        public string Name;
        [SerializeField]
        string Tag;
    }
    [SerializeField]
    ClassData classData;
}

f:id:PaperSloth:20200525124828p:plain

おまけ Inspectorで上書きした値が保存される場所

Inspector上で書き換えた値はScene fileに紐付いて保存されています

例えば以下のように設定しておいた場合
f:id:PaperSloth:20200525123612p:plain

scene.unity ファイルをエディターで開いてgrepすると
以下のように保存されていることが確認できます

MonoBehaviour:
  ... (省略)
  m_EditorClassIdentifier:
  structData:
    Value: 2000
    Name: Enemy
  classData:
    Tag: Player

普段中身を見ることは少ないとは思いますが
デカいSceneを開かないでgrepして値を追いたい時など何かしら使うケースがあるかもしれません

UE4 KeyConfig作成用のPluginを公開しました

目次

概要

UE4でのKeyConfigの作成の参考になるPluginを公開しました。
鋭意開発中でまだまだ機能不足が目立ちます。

ProjectDirのPlugins以下に以下のPluginsを入れれば動作します。
github.com

ProjectSettingsのAction Mapping / Axis Mappingで設定した名前を元に変更します。

初期のバージョンでの実装

現在用意しているノードについて
f:id:PaperSloth:20200511131004p:plain

- ChangeMapping
Action/Axisどちらかのキーの変更用ノード
  BindName : Action/Axis Mappingで設定した変更したいキーの名前
  Key : FKeyの構造体、AnyKey等で取得するのが楽です
  BindType : ActionかAxisのどちらか
  PlayerIndex : 変更を適用したいPlayerControllerの番号(デフォルトは0)
- ChangeActionMapping
Action Mappingで設定したキーの変更用ノード
- ChangeAxisMapping
Axis Mappingで設定したキーの変更用ノード
  Scale : 基本的には-1.0 - 1.0 で指定 ProjectSettingsのAxis Mappingと同様
- GetAllActionMappingNames
Action Mappingで設定したキーの名前一覧を取得するノード
  ActionNames : Action Mappingで設定したキーの名前一覧
- GetAllAxisMappingNames
Axis Mappingで設定したキーの名前一覧を取得するノード
  AxisNames : Axis Mappingで設定したキーの名前一覧
実装概要

GitHubに公開してるので、実装をそのまま見てもらえれば早いんですが、簡単に概要だけ書きます。
まず、FKey構造体を使用するためBuild.csのPublicDependencyModuleNamesにInputCoreを追加しておく必要があります。

PublicDependencyModuleNames.AddRange(
    new string[]
    {
        "Core",
        "InputCore", // 追加
    }
);

Mapping系について
PlayerInputからActionMappings配列内の同名のAction/Axisを削除し、新しくKeyを設定して追加しています。
Axisに関しても同様の実装になっています。

const APlayerController* const PC = UGameplayStatics::GetPlayerController(WorldContextObject, PlayerIndex);
UPlayerInput* const PlayerInput = PC->PlayerInput;
PlayerInput->ActionMappings.RemoveAll([&ActionName](const FInputActionKeyMapping& NowMapping)
{
    return (NowMapping.ActionName == ActionName);
});

const FInputActionKeyMapping AddMapping(ActionName, Key);
PlayerInput->AddActionMapping(AddMapping);

GetAllXX系について
こちらはUInputSettingを取得してそこに登録されているAction/Axis名を取得して
配列に格納して返しているだけです。

ActionNames.Empty();

const UInputSettings* Settings = GetDefault<UInputSettings>();
for (const FInputActionKeyMapping& Action : Settings->GetActionMappings())
{
	ActionNames.Emplace(Action.ActionName);
}


特に細かく語るほどのことがないシンプルな実装なので、C++を書ける人はPluginを導入せずに自分で書いた方がなにかと都合がいいと思います。

追記: 大幅に仕様を変更し、サンプルプロジェクトを追加

以前の実装との違い
更新内容
1. Gamepadでのマウスカーソル移動が可能になった
2. Sampleを用意したため、より具体的な使い方のイメージができるようになった
3. iniへの書き込みを行うようにしたため、変更内容が保存されるようになった
4. Keyboard, Gamepadそれぞれでの変更が可能となった

なくなった機能
1. Axis対応の破棄(機能不十分のため一旦見送り)
2. 複数PlayerControllerに対応できなくなった
対応するにはコードの書き換えが必要です

まずは最小構成のNodeのサンプルです。
登録したAction名に対して任意のKeyで上書きするというものです。
一番シンプルな使い方です。
f:id:PaperSloth:20200516004514p:plain

続いてNodeの一覧です。
f:id:PaperSloth:20200516004506p:plain
ざっくり分けると以下の3カテゴリに分かれています。

  • Keyの更新
  • Gamepadでのマウスカーソル有効化/無効化
  • Key情報の検索

サンプルの画面がこちらです。
Keyboard, Gamepadそれぞれで任意のKeyの割当ができるようなサンプルを用意しました。
f:id:PaperSloth:20200516004458p:plain

参考資料

スライド内のp.48
UE4を用いたTPS制作事例 EDF:IR 地球を衛る兵士の作り方

こちらのPluginにRebind系とGamepadのUMGでの使用するための機能が一通り揃っていますので、こちらを使用されるのも良いかと思います。
GitHub - EverNewJoy/VictoryPlugin: Rama's Victory BP Plugin
https://github.com/EverNewJoy/UE4GamepadUMG

UE4 HoudiniEngine for UE4を使ってHDAをUE4で使う方法

目次

環境

UE4.23.1
Houdini Indie 18.0.287
Houdini Engine for Unreal 4.22.3/4.23.1

前準備

UE4とHoudiniはインストール済の前提で進めます。
Houdiniのインストール時にHoudini Engine for Unrealにチェックを入れておくと良いでしょう。
f:id:PaperSloth:20200503145953p:plain

また、Houdini Engineの機能はHoudini Apprenticeでは使用できません。
HDA(Houdini Digital Assetの作成までは行えたと思いますが、UE4側で使用できないはずです。

実際に制作してみる

今回は説明のためにSphereをHDA化してUE4に持っていきます。
パラメーターを吐き出す流れさえ理解すれば、あとは自由に応用が効くと思いますので非常に簡単な例としました。

少し凝ったものを作成したい方は以下のSideFXのサイトにUE4向けのチュートリアル動画が参考になると思います。
動画ではHoudini FX 15.0.299を使用しており、バージョンがかなり古くなっていますが大きく困るポイントは少ないと思います。
バージョン違いでは色々と問題が発生するため慣れていない場合は極力同じバージョンか近いバージョンのものを使用する方がよいでしょう。
https://www.sidefx.com/ja/products/houdini-engine/plug-ins/unreal-plug-in/

Houdini 側の作業

大まかな流れ
1. geometry作成
2. sphere作成
3. subnet化
4. exportするパラメーターの設定
5. HDAとして保存

1. geometry作成
Houdiniのいつもの流れですね。
Network Viewでgeometryを作成します。
f:id:PaperSloth:20200503151832p:plain

2. sphere作成
1.で作成したgeometryをダブルクリックか i キーで中に入ります。
中に入るとsphereを作成します。
f:id:PaperSloth:20200503152035p:plain

sphereのPrimitive TypeをPolygonに変更しておきます。
f:id:PaperSloth:20200503152555p:plain

3. subnet化
subnet化は複数のノードの塊を1つのパッケージにする機能ですが
HDAとして出力する際にも役立ちます。

sphereノードを選択してNetwork View右上の箱のアイコンからsubnet化できます。
ショートカットキーはShift + Cです。
f:id:PaperSloth:20200503152933p:plain

以下のようにsubnetノードが作成されます。
f:id:PaperSloth:20200503153048p:plain


4. exportするパラメーターの設定
subnetノードを選択してGearのアイコンのEdit Parameter InterfaceからexportするParameterを設定します。
f:id:PaperSloth:20200503153614p:plain

Edit Parameter Interfaceのwindowが開いたら
From Nodesタブに切り替え、sphereのFrequency (freq)を右のExisting Parametersにドラッグアンドドロップします。
パラメーターを選択してして -> ボタン押下でも可能です。
f:id:PaperSloth:20200503154015p:plain

パラメーターを反映できたことを確認したらAcceptボタンを押下して閉じます。
f:id:PaperSloth:20200503154114p:plain

subnetの中に先程設定した Frequencyが追加されていれば成功です
f:id:PaperSloth:20200503154236p:plain


5. HDAとして保存
subnetノードを選択して右クリック -> Create Digital Asset... からHDA化します。
f:id:PaperSloth:20200503154356p:plain

Operator Nameにsphereと入力します。
するとOperatar Labelも自動で変更されます。
Save to Libraryには保存したいパスにsphere.hdalcとしてAccpetを押下します。
f:id:PaperSloth:20200503154506p:plain

すると以下のようにEdit Operator Type Propertiesが開きます。
ここでは特に変更を行わなずSave to Libraryのpathが正しいことを確認したらAcceptを押下します。
f:id:PaperSloth:20200503154925p:plain

以上でHoudini 側の作業は終了です。

HDAをUE4にimportする

UE4側では4.23.1で新規にBlankのTemplateでプロジェクトを作成しました。
既存のプロジェクトでも特に問題ありません。

先ずプロジェクトを起動したらHoudini Engineがインストールされていることを確認しましょう。
Edit -> Plugins のInstalled 以下にHoudini Engineが存在し、Enabledになっていることを確認します。
f:id:PaperSloth:20200503155252p:plain
f:id:PaperSloth:20200503155313p:plain

有効になっていれば、特に設定することはありません。
先ほど作成したsphereのHDAをContent BrowserにドラッグアンドドロップするかImportボタンを押下してImportします。
f:id:PaperSloth:20200503155451p:plain
f:id:PaperSloth:20200503155615p:plain

ImportしたHDAをLevel上に配置したら完了です。
DetailsからFrequencyを変更してみて反映されることを確認しましょう。
f:id:PaperSloth:20200503160303g:plain

また、Houdini側で設定をしていない場合でもUE4側からMaterialを変更したりStatic MeshとしてBake(保存)することができます。
importしたHDAを選択してDetails内のHoudini Generated Meshes以下から可能です。
Bakeを押下すると現在の設定のMeshが別アセットとして保存されます。
Materialを変更すればもちろん見た目に反映されます。
f:id:PaperSloth:20200503163223p:plain

それぞれパラメーターを変更してStatic MeshとしてBakeしたものです。
f:id:PaperSloth:20200503163528p:plain

Bake後は通常のStaticMeshと同様ですので、UE4側の設定でLODを作成したりすることももちろん可能です。

Materialを変更した例
f:id:PaperSloth:20200503163854p:plain

おまけ
importかexportの設定に失敗していたり、Houdini Apprenticeだと以下のようにロゴのみの表示になってしまいます。
f:id:PaperSloth:20200503162513p:plain

追記 Unreal Materialの適用方法

Houdini 側でUE4のMaterialへの参照を持たせた状態でのHDAの作成が可能です。
HoudiniにはUnreal Materialというノードが用意されています。
f:id:PaperSloth:20200503171641p:plain
f:id:PaperSloth:20200503171711p:plain
f:id:PaperSloth:20200503171733p:plain

Stringの説明文にあるように、UE4のプロジェクト内での相対パスを設定してやればよいようです。
UE4側で使用するためのMaterialを用意しておきましょう。
Content直下にM_TestHDAというBaseColorに赤を割り当てたMaterialを用意しました。
f:id:PaperSloth:20200503171913p:plain
f:id:PaperSloth:20200503172018p:plain

再びHoudiniの作業に戻ります。
UE4のパスのContentはGameと解釈されます。
そのため、Material'/Game/(Materialへのpath)/(MaterialName.MaterialName)'
といったパスを設定してやります。
今回の例ではContent直下のため、以下のようになります。
「Material'/Game/M_TestHDA.M_TestHDA'」
f:id:PaperSloth:20200503172115p:plain

あとは先程同様にHDAとして保存し、UE4にImportします。
これで設定したMaterialが反映されていることが確認できました。
f:id:PaperSloth:20200503172640p:plain
因みにEngineContent以下のMaterialを適用したい場合のパスは/Game/ を/Engine/ と置換してやることで使用可能です。

追記 作成したHDAの更新方法

Houdini 側の作業
Assets -> Edit Assets Properties... -> subnet Name
これでEdit Operator Type Propertiesが開かれます。
そこで、Apply またはAcceptを押下することでHDAが更新されます。
f:id:PaperSloth:20200504173033p:plain

UE4側の作業
上記の更新を行った後にHDAを選択してDetails内からRebuild Assetを押下することで更新されます。
f:id:PaperSloth:20200504173254p:plain

参考資料

https://www.sidefx.com/ja/products/houdini-engine/plug-ins/unreal-plug-in/

https://www.sidefx.com/forum/topic/49570/


また、今回は紹介できませんでしたがSideFX Labs内に
NiagaraやTerrain関連のノードも用意されており、機会があれば紹介させていただきます。
f:id:PaperSloth:20200503173906p:plain