今年の4月にUE5が正式公開され、サンプルやショーケースも色々と配布されています。
その中で、The Matrix Awakens: An Unreal Engine 5 Experience(通称Matrixデモ)の街並みのデータが含まれた
について、街並みの作り方についてワークフローの側面から調査しました。
Cityサンプルが更新されているか分かりませんが、調査したのはUE5.0.0がリリースされた直後のデータになります。
概要
Cityサンプルに関するドキュメントは、公式サイトにもあります。
最終的な街並みの形状はHoudiniで作られています。UE5では、Houdiniで作られたPBC(ポイントクラウド情報)を元にRuleProcessorによってActorやBlueprintを生成しています。
そのため、街の形状を変えたい場合は、Houdiniで調整を行い、PBC経由で再生成することになります。
また、Cityサンプルで使用されているHoudiniプロジェクトは、Cityサンプルフォルダ内の CitySample_HoudiniFiles.zip にまとめられています。
使い方に関しては、
で、ずしさんがTwitterスレッドにまとめてくださっているので参考にしてください。
CitySample_HoudiniFiles.zipにはSmallCityのHoudiniプロジェクト(*.hip)が入っていて、UnrealEngine側の/Game/Map/Small_City_LVLの内容と対応していますので、見比べながらデータを確認していくと理解しやすいと思います。
RuleProcessorについて
RuleProcessorはCityサンプルで使われているプラグインです。
エンジンプラグインではありませんが、比較的汎用的に作られているようなので、プロジェクトに取り込んで使うこともできると思います。
私は、将来的にエンジンプラグイン化されることを期待しています。
RuleProcessorの仕組み
上図のように、PBCの情報を元にRuleSetの記述に従いActorやBlueprintをレベル内に配置する。というのがメインの機能になっています。
RuleSetとPBCはMappingという単位で扱われ、このMappingと生成されたActorやBlueprintなどは関連付けが行われています。
そのため、Mappingごとに
- Actorなどの生成(再生成含む)
- 生成したActorなどの削除
- 生成したActorなどの一覧を取得
といったことが可能になっています。このRuleSetを間違えた!となっても、その時に生成されたActorだけ消してやり直しが可能です。いちいち、生成されたActorを探して削除したり、UNDOに頼る必要はありません。
また、Cityサンプルではほぼすべての要素がこのRuleProcessorで作成されています。
試しにRuleProcessorで作成されたActorを全て削除すると、表示されるメッシュは上図のようにエンパイアステートビルや議事堂などの HeroBuilding と呼ばれるユニークな建物のみになります。
他に残っているActorは、DirectionalLightやSkyLight、PostprocessVolumeなどのライティング関連。群衆制御モジュールやWorldPartitionなどのワールド全体で動作させる制御モジュールのみになっています。
RuleSetについて
RuleSetアセットの仕組み
Small_City_FULL_buildings_Roof_Geoを参考に解説していきます。
RuleProcessorでは、このRuleSetと対象となるPBCを対で指定して、実行します。
RuleSet内では、まずはMetadataの内容に沿って対象となるポイントデータのフィルタリングが行われています。
最初の Metadata: Select rooftops (赤枠)では、unreal_instanceがSM_arbitrary_roof_を含む名前を条件にしています。
その下にはMatches FilterとUnmatchedに分岐して、フィルタ条件に該当したもの、または該当しなかったものに分岐して処理が継続できます。
次の Metadata: building (緑枠)では、Metadata: Select rooftopsで該当したポイントデータに対して、typeがbuildingと等しいかを条件にしています。
さらにその次、 MultiActor: Building no Col ではMetadata: buildingで該当したポイントデータを基にActorを生成する処理です。
Name Pattern(黄枠)で、生成されるActorの名前を指定できますし、Templatesの項目内を変更すればコリジョン設定の変更やLOD設定の変更、Visibleフラグの調整なども行えるようになっています。
RuleSetを分けるべきか否か
結論から言うと、適度に分けるべき。と思いますし、実際CityサンプルのRuleSetの構成もそうなっていました。
Small_City_FULL_buildingsを参考にみてみると、一番最初の条件は先ほどのSmall_City_FULL_buildings_Roof_Geoと全く一緒です。ただし、続く処理はUnmatchedに書かれていて、unreal_instanceがSM_arbitrary_roof_を 含まない ポイントデータを処理しています。
MatchesFilterとUnmatchedにそれぞれの内容を記述していけば、Small_City_FULL_buildings_Roof_GeoとSmall_City_FULL_buildingsは1つのRuleSetにまとめる事が可能です。
では、なぜ2つのRuleSetに分けているか。
それは、RuleProcessorのMapping単位で生成されたActorが管理されているからです。
RuleSetをわけて、同じPBCからでも別のMappingとして扱うことで、再生成や削除する際にそれ毎に処理が可能になります。
今回の例だと、ビルの外壁と天井で分けていますので、それぞれで確認/修正する必要があった。ということだと思います。
Houdiniでやっていること
RuleProcessorの仕組みで触れたように、ほぼすべての要素はHoudiniから出力されたPBCを基に配置されています。
Houdiniで何をやっているかについては、先日行われた
が詳しいです。
Houdini内では、
- レイアウト
- 道路の設定
- 高速道路の設定
- 区画の生成
- 歩道の生成
- トラフィック情報の生成
- 群衆制御にも使用
- ビルの生成
- 道路や歩道以外の地表埋め
- 道路上の装飾品
- ポールや信号機、街路樹など
- デカール
- 横断歩道や車道のレーン、道路の汚しなど
- オーディオ
- 環境音源の配置
といった街を構成する要素をほぼすべて作っています。
hip(Houdiniのプロジェクトファイル)内の Processor1 のノードがメインの処理場で、全景は上図の通りです。概ね振られた数字の順に処理が行われていて、黒い線で区切られた単位で依存関係があるようです。
ここで生成した結果をPBCに出力(明るめの灰色の部分)し、UnrealEngineのRuleProcessorで使用します。
UnrealEngineでやっていること
RuleProcessorによるActorやBlueprintの生成
Houdiniで生成したPBCには、どのアセットを配置するかの情報が書き込まれています。
それを基に、RuleProcessorのルールに従って、LevelInstanceActorであらかじめ作ったBPや、InstancedStaticMeshComponentを含んだActorを生成して配置しています。
詳しくはRuleSetについてで触れていますので、そちらの項目を見てください。
LevelInstanceActorの作成
UE5からLevelInstanceActorというキットバッシュでアセットを作る仕組みが用意されました。
機能の詳細は、
上記ドキュメントを参照してください。
この機能を使うことで、StaticMeshアセットを組み合わせて、最適な1つのActorを作ることができます。
Cityサンプルでは、上図のように複数のStaticMeshを組み合わせて1つのPropを作っています。
それぞれのStaticMeshは自動的にInstancedStaticMeshとして格納されるため、効率よく描画される仕組みになっています。
また、このアセットからFBXをエクスポートすることも可能で、そのFBXをHoudiniでも利用していました。
全体を見ての感想
UnrealEngineでやっていることが少ない!
今までHoudiniEngineを触ってきた経験から、HoudiniAssetActorなどを駆使してエディタ側でアセットの生成、その結果をエディタ上でカスタマイズ。といったワークフローかと思っていました。
しかし、UnrealEngineではHoudniで作られた情報を基に配置しているだけでした。確かにその方がデータの堅牢性はあり、何らかの理由で再生成する際も失われる作業が無くて済みます。
TechTalkなどの各種動画を見るとHoudiniAssetActorを使っているシーンもあるので、単体テストとしてHoudiniAssetActorを使って機能を確認し、PBCを出力するhipに統合していく。といった流れだったのかもしれません。
今まで、「ワールドの構築はエディタ上で」という方針でしたが、今後は「ワールドの構築はHoudiniで」となっていくのかもしれません。
プロシージャルルールの作成が肝!
このワークフローを採用する場合、ほぼすべてHoudiniで作られていることからHoudiniを扱える人が多数必要になるかもしれません。しかし、それよりプロシージャルルールを作れる人の確保が急務かもしれません。
TechTalkの動画を見てもらうと分かりますが、街並みの要素を分解/再構築する必要があり、どのようなルールにすれば目的の街並みが再現できるか。を考えていく人が必須です。
それには専門知識が必要になってくるため、専門知識のないエンジニアに丸投げは厳しいと思われます。
しかし、プロシージャルルールさえあれば、Houdini上の実装はエンジニアの領分にできそうなので、いくらかは人材確保の難易度も下がりそうです。
作ってしまえば、イテレーションやバリエーション作成はかなり楽
概要で紹介したTweetにもあるように、この仕組みができてしまえば、レイアウトの異なる街はいくらでも作れます。
また、スタイルの異なる街並みを作るのも比較的容易だと思います。(構成パーツを差し替えればいい)
そのため、コンテンツを次々に作る必要がある運営型タイトルに向けては魅力的な選択肢になりそうです。ただし、仕組みを作成するコストが高いので、それを乗り越えられるかがカギとなりそうです。
見えない部分は気にしなくてOK!
この画像はビルの内側から、隣接ビルの方向を見た状態です。このように
- 隣接ビルとの隙間が無くても出口が作られる
- ビル同士はめり込んでいる
という状態で、見えない部分は気にしていないようです。
見えない部分にも頂点情報がありますが、Naniteで処理されていれば概ね見える部分の頂点処理しか行われないため、無駄な処理負荷は掛かりません。
次に問題になりそうなのはディスク/メモリ容量ですが、Cityサンプルにおいてはアセットはパーツ単位で管理されていて使いまわされています。そのため、容量も問題にはならないようです。
あとがき
以前まとめたAnimToTextureプラグインもそうですが、Cityサンプルに入っているプラグインは色々と使いどころがありそうです。C++が出来る人は、これをベースにカスタマイズしても面白いかもしれません。
他にも、オーディオ関連のWorldAudioDataSystemやSoundscapeのプラグインもなかなか興味深い設計で、「大量に配置しつつも再生量を制御する仕組み」としては、こんな方法もあったのか。と参考になります。こちらも、時間があればまとめてみようかと思います。
Cityサンプルは、Matrixデモに使われたこともあって見た目も素晴らしいですが、それを支えるワークフローも興味深いものが多いので、興味のある方はぜひ覗いてみてください。
参考資料