この記事はHoudiniアドベントカレンダー2021 15日目の記事です。
※追記 12月23日
共有フォルダーの設定が非公開になっていました。
現在は公開になっているので、記事最後のリンクから作成したファイルをダウンロード出来ます。
##はじめに
こんにちは!
Houdiniのアドベントカレンダーに参加するのは初めてでちょっと緊張していますが、最近Houdini Engine UE4をプロジェクトで使っていて、調べてる内にBPからHDAを操作できるAPIが存在している事に気付き、あまり知られてなさそうだけどこれは便利なのではと思ったので共有させて頂きます。
##作るもの
今回作るのはこんな感じの、選択したHDAの初期パラメーターやインプットジオメトリーを設定した状態でスポーンさせるランチャー的なEUWです。
ついでにベイクの方法も選択して、ベイクの実行もこのEUWからやってしまいます。
こうする事で、HoudiniAssetActor自体のパラメーターを極力触らないでHoudini Engineを扱う事が出来ます。
ちなみに今回の記事はこちらの公式ドキュメントを元にしていますので、もっと詳しく知りたいという方は公式ドキュメントの方もご一読される事をお勧め致します。
PythonやC++からなんかもHDAを操作できるみたいなので、BPなんてしゃらくせー!という方は是非
Houdini Engine for Unreal: Public API
##対象者
・ある程度UE4のBPが扱える方
・HDAを作成でき、Houdini Engine UE4を使った事がある、もしくはこれから使っていきたい方。
・Houdini Engineマスターではない方。
##環境
Houdini Indie 19.383 Python3
Houdini Engine V2.0 - H19.0.383
Unreal Engine 4.27.2
##そもそもなんでEUWとBP?
そもそもEUWとBPをHoudini Engineと組み合わせるに至ったきっかけですが、Houdini Engineって強力な一方、メッシュの指定やセッションの接続等初期設定が煩雑だったり、ベイク周りの自由度が低いせいでベイク後にポストプロセス的な作業が必要だったりと、意外と実際のプロジェクトでは使いにくいなと思う所があるんですよね。
特にHoudini Engineに慣れている方であれば問題ないのですが、Houdiniを使った事がないアーティストに使ってもらおうと思った場合、その辺の手順が分からずトラブルになったり。
そこで、ツールの始点となるランチャー的なものをEUWで用意してあげれば、初期設定なんかをそっちで先に済ませてあげる事で、スムーズにHoudini Engineをワークフローに取り入れられるのではないかと思ったのがきっかけです。
##HDAを用意する
それでは、まずHoudini Engineで使用するHDAを用意します。
このHDAは何でも良いのですが、今回私はとてもシンプルな、ベースメッシュを選択してその上に"unreal_instance"アトリビュートを持ったポイントを発生させるHDAを作成しました。
ノードネットワークはこんな感じ。
BaseMesh(World)がUE4上のHoudini Inputsになり、object_mergeでインスタンスで使用するStaticMeshを受け取ります。
一つポイントとしては、今回UE4内でインスタンスに使用するメッシュはユニークなものを生成するのではなく、既存のコンテンツブラウザーにあるものを使用したいので、UE4上で選択したメッシュから"unreal_input_mesh_name"アトリビュートを取り出し、それを"unreal_instance"にリネームしてポイントアトリビュートとして格納しています。
また、ベースメッシュを読み込むInput1のラベル名を、**"BaseMesh(World)"としておきます。
ここのラベルについては任意なのですが、"World"**という単語を入れておく事で、HDAをUE4に読み込んだ時に、自動で"Wolrd Outliner Input"タイプを使用してくれるので、この単語を入れておきます。
##HDAをテストしてみる
まずはEUWと組み合わせる前に、素のままでHDAを使った時のフローを確認します。
コンテンツブラウザーからレベルにD&DでHoudiniAssetActorを生成。
Houdini Inputsセクションの"Start Selection"を使用してベースメッシュとなるStaticMeshActorを選択。
Houdini ParametersのInstance Meshに適当なスタティックメッシュを読み込めば、こんな感じでインスタンスされたメッシュが表示されるかと思います。
あとはこのHoudiniAssetActor上のパラメーターを調整してベイクするのが基本のフローですが、このフローをEUWからコントロールしてみたいと思います。
##EUWを作る
HDAの用意ができたので、今度はこのHDAをコントロールするEUWを作成します。
この辺りのEUWの作成方法についてはUE4の使い方の範疇になりますので、ざっくりと割愛させて頂きます。
詳しくEUWについて知りたいという方はこちらの記事なんかがオススメです。
株式会社アンナプルナ様の記事
【UE4】Editor Utility Widgetについてのあれこれ
で、作ったEUWがこちらになります。
Single Property Viewを使って、レベルに発生させるHDAオブジェクトとインスタンスするメッシュを選択できる様にしています。
HoudiniAssetオブジェクトもStaticMeshオブジェクトもどちらもハードリファレンスです。
"Bake"ボタン横のプロパティビューは、後々ベイクオプションを変更する為に使用するので今はまだ機能しません。
HoudiniAssetオブジェクトを選択するProperty Viewには、デフォルトで使用したいHDAを登録しておくと、EUWを起動した時にいちいち選択しなくて済むので楽かもしれません。
##4.EUWからHDAを操作する
ではここからが本題。
####セッションの接続とHDAのスポーン
まずは、とりあえず"Spawn"ボタンが押された際にHoudini Engineのセッションを接続してくれるようにします。
"GetHoudiniEnginePublicAPI"関数でHoudiniEngineAPIのインスタンスをもらい、"Is Session Valid"で既にセッションが接続されているか確認します。
セッションが停止していたら"Create Session"関数で新しいセッションを作成します。
これでHoudiniAssetActorが作成された時にセッションが接続されていなくても、ボタンを押すだけで接続してくれる様になります。
次に、EUWで選択したHDAを発生させてみます。
"Instantiate Asset"に変数として格納していたHoudiniAssetオブジェクトを渡せばOKです。
しかしこれだけではただHoudiniAssetアクターを発生させただけなので、あまりメリットを感じませんね。
この発生させたHDAにEUWで設定したパラメーターを渡してみたいと思います。
####HDAのパラメーターを変更する
まずは、"Instantiate Asset"の返り値(Houdini Public API Asset Wrapper)から、"Assign On Pre Instantiation Delegate"を選択し、"Bind Event to On Pre Instantiation Delegate"というノードを出します。
このDelegateは何かと言うと、公式のドキュメントによれば、HoudiniEngine側で行われる処理のそれぞれのタイミングでUE4に返してくれるイベントディスパッチャーの様なものとの事。
HoudiniEngineの処理のタイミングはUE4の管理外にあるので、このDelegateを使ってHoudiniEngineが今どの処理を行っているのかを把握する様です。
今回使用する"On Pre InstantiationDelegate"は、説明にある様にHDAのインスタンスが生成される前にブロードキャストされるもので、このタイミングで初期状態としてパラメーターの値を変更するのに使います。
他にも色々このDelegateはあるので、HDAに掛けたい処理に応じて使っていく形になります。
で、そのPre Instantiation Delegateを使って、EUWのパラメーターの数値をHDAに渡したネットワークがこちらになります。
基本的にHDAが生成された時にそのWrapperとして生成されたHoudini Public API Asset Wrapperオブジェクトに対してパラメーターの処理を行って行きます。
ここでのパラメーター名は、HDAの直接のパラメーター名になります。
####インプットの設定
次に、ベースとなるベースメッシュ、インスタンスで使用するスタティックメッシュをHDAのインプットに設定していきます。
インスタンスについては、EUWで設定したメッシュを取得してWrapperに渡すだけで良いのですが、ベースメッシュについてはHDAの生成時に選択していたアクターを使用する事にします。
これらのジオメトリーインプットはPre Instantiation Delegateでは設定できないので、代わりに Post Instantiation Delegateを使用します。
まずはインスタンスで使うメッシュの設定ですが、HDAのインプットの設定は普通のパラメーターとは異なり、"Create Empty Input"というそれぞれのインプットタイプに応じた空のインプットオブジェクトを作ってくれるノードを使用し、このオブジェクトにインプットで使用したいメッシュをバインドしていく形になります。
インスタンスメッシュは"Geometry Input"タイプですので、"HoudiniPublicAPIGeoInput"クラスをこちらのノードで設定します。
あとは、そのインプットオブジェクトにEUWで設定したメッシュを"Set Input Objects"で格納し、"Set Input Parameter"でそのインプットオブジェクトを指定のインプットパラメーターに渡してあげればOKです。
これでHDAの生成時にEUW上で設定したスタティックメッシュがインスタンスとして使用されるようになりました。
ベースメッシュの設定も同じ要領になります。
まずは先に、ボタンが押された時点で選択してあるアクターを変数として格納しておきます。
(4.26では"Get Selected Level Actors"が使えたのですが、4.27では"Get Selected Actors"になっていました。)
次に、インプットオブジェクトを作成します。
ベースメッシュはWorld Outlinerから受け取りたいので、ここでは"HoudiniPublicAPIWorldInput"クラスを使用します。
あとはインスタンスメッシュと同じ要領で、選択されたアクターを"Set Input Objects"に渡し、そのインプットオブジェクトをWrapperのインプットに渡せばOKです。
この時先ほどとは違い、"Set Input At Index"を使います。
ここまで来れば、インスタンスを発生させたいアクターを選択して"Spawn"ボタンを押すだけで、EUW上でインスタンスに使用したいスタティックメッシュの選択、初期値のパラメーターの設定が反映された状態でHoudiniAssetActorがスポーンする様になったかと思います。
HDAの初期設定が大分楽になりましたね!
####ベイク機能
最後に、生成したHoudiniAssetActorをベイクする機能も足したいと思います。
まずは、ちょっとネットワークがごちゃごちゃしてしまうので、HDAのWrapperを変数として格納しておきます。
そしてこの格納したWrapperを"Bake All Outputs with Settings"に繋げば完成です。
これだけで、EUWからスポーンしたHoudiniAssetActorをベイクする事が出来ます。
もしEUWから生成したHoudiniAssetActorだけではなく、任意でコンテンツブラウザーから生成したHoudiniAssetActorをベイクしたい場合などは、下の様なノード達を使えば好きな様にHoudiniAssetActorをWrapperに格納する事が出来ます。
最後にベイクのオプションですが、"Bake All Outputs with Settings"の"In Bake Option"を右クリックし、Promoteします。
そうすると、このような"EHoudini Engine Bake Option"という変数ができるので、"Bake Option"と変名。
ベイク用に作ったが機能していなかった"Property View"の"Property Name"に"Bake Option"と記入。
最後にこちらの"Property View"をセットすれば、EUWからベイク方法も選択できるようになります。
##5.おわりに
今回はHDAの初期設定をしてスポーンさせる、ベイクを実行するだけという非常なシンプルなツールになりましたが、他にも実際にライブでパラメーターを変更したりと色々出来そうではあるので、非常に可能性があるのではないかと思います。
実際にプロジェクトではベイクした後にPostBakeDelegateを使いそのままPythonを実行して生成されたBlueprintを編集するプロセス等も行っていたので、このEUWとHoudini Engineに更にPythonも加えれば、より一層Houdini Engineを使ったワークフローが使いやすく、強力になる様に思えます。
今回は長くなってしまったのでここまでになりますが、これを機にHoudini Engineを触る方が増えたり、何かしらのヒントになれば幸いです。
作成したHDAとEUWはこちらにアップしておきますので、ご自由に使ってみてください。
https://drive.google.com/drive/folders/1w7Tsbdgei9KeQ7fAjMj4oNa9JvEMs6Wt?usp=sharing
では皆様良いお年を!