新年あけましておめでとうございます!
大変遅刻しましたが、Unreal Engine (UE) Advent Calendar 2023の13日目の記事です。
UE5.2からプロシージャルコンテンツ生成フレームワーク (PCG:Procedural Content Generation Framework) が追加されました。
PCGを利用すると、大量のStaticMeshの配置などの手動では大変な作業を自動化に役立ちます。
Houdini Engine for Unreal Engineでも同じことは可能ですが、UE内で作業が完結するため、よりイテレーションを高速に回せることがメリットだと思います。
最近PCGを使う機会があったので、PCGについて最初に知りたかったポイントや、よく使うパターンの実践TIPSをまとめます。
執筆時のバージョンはUE5.3.2です。
UE5のサンプルプロジェクトはGitHubに公開しています。
- github.com/gam0022/UE5_Examples
- Content/PCGExamples フォルダを参照してください
PCGのセットアップ
以下のプラグインを有効化してください。
- Procedural Content Generation Framework
- Procedural Content Generation Framework Geometry Script Interop
PCGの基本的な使い方
PCGの基本的な使い方については、たくさんの入門記事があるため、今回は割愛します。
Level上にPCG Volumeを作成して、PCGのGraph InstanceにPCG Graphを設定します。
PCGの最初に知りたかったポイント
Example01: シンプルなPCGの例
Landscape上にランダムにMeshを配置し、Mesh同士がぶつからないようにするシンプルなPCGの例です。
このPCGでは、以下の4ステップの処理を行っています。
- ポイントの生成
Get Landscape Data
でLandscapeを取得Surface Sampler
でLandscapeに対してポイントを生成
- ポイントの処理
Transform Points
でランダムな移動と回転
- ポイントのフィルター
Bounds Modifier
でバウンディングボックスを調整Self Pruning
で自己干渉しているポイントを消去
- StaticMeshを生成
Static Mesh Spawner
でStaticMeshを生成
PCGではポイントを生成してから、ポイントのAttributeを何かしらの方法で加工し、最後にStatic Mesh SpawnerでStaticMeshを生成という流れになります。
そのため、ポイントにどんなAttributeが存在していて、どのように値が変化するのかを意識することがとても重要です。
この4ステップの流れは複雑なPCGでもほとんど変わらない定型パターンになります。
Inspect機能でAttributeの内容を確認する
「ポイントのAttributeの内容をInspect機能で常に確認しよう」
この記事で一番伝えたかったポイントです。Attributeの変化を意識することが、PCGマスターへの近道です。
Houdiniの経験がある方は実感できるのではないでしょうか。
参考記事: 絶対に挫折しないHoudini入門 4 - オブジェクトとジオメトリ|aoi
PCGのポイントはAttributeを持っています。これらがAttributeの具体例です。
- Position
- Rotation
- Scale
- BoundsMin / BoundsMax
- Color
- Density
Inspect機能は、ポイントのAttributeを内容を確認するための機能です。HoudiniのGeometry Spreadsheetに相当する機能です。
PCGの上部のタブから No Debug object selected
と書かれている項目をプルダウンで変更し、現在のPCG Graph名 / PCG Compornetを選んでください。
ノードを右クリックしてInspectにチェックすると、そのノードの処理時点のPointの持つAttributeが表示されます。
ショートカットとして、ノードを選択してからAキーを押してもInspectが有効になります。
Inspect中のノードは左上に黄色い●が表示されます。
Debug機能でビューポート上でポイントを確認する + Self Pruningで重なりを除去
Debug機能はViewport上でポイントを可視化する機能です。ノードを右クリックしてDebugにチェックするか、Dキーを押すことで有効になります。
Debug中のノードは左上に青い●が表示されます。
ビューポート上の白・黒・グレーの箱がDebugの表示です。
箱の色はDensityに対応しており、箱の大きさは Scale
と BoundsMin / BoundsMax
に対応します。
Self Pruning
はポイントが持つバウンディングボックスのAttributeに対して判定が行われます。
そのため、ステップ3のポイントのフィルターでは、まず Bounds Modifier
でバウンディングボックスを調整してから Self Pruning
しています。
Inspect機能とDebug機能をつかって、ポイントのAttributeの変化を確認することが、PCGの作業効率アップやPCGへの理解度がアップにつながります。
PCGの実践TIPS
PCGでよく使いそうなパターンの実践TIPSを紹介します。
Example02: 特定のStaticMeshを避けて配置
特定のオブジェクトを避けて配置する例です。
まず手動でテーブルのStaticMeshを配置し、ActorのTagsに SM_Table
を設定します。
対応前:Example01のままだと、テーブルと椅子が重なり合ってしまいます。
対応後:重ならないようになりました。
これがPCG Graphです。オレンジ色の枠で部分がExample01から新しく追加した処理です。
Get Actor Dataの設定
Get Actor Dataはアクターを取得するノードです。
- Actor Filter: All World Acotrs
- Must Overlap Self: ON(Volumeの範囲内だけに限定します)
- Actor Selection Tag: SM_Talbe(StaticMeshに設定したタグを指定)
- Select Multiple: ON(テーブルが複数ある場合はONにします。基本的にONで良いと思います)
- Mode: Get Single Point
- Merge Single Point Data: ON
Differenceの設定
Differenceは差集合を計算するノードです。今回の例では、テーブルのバウンディングボックスと重なる椅子を削除します。
- Density Function: Binary
Example02のまとめ
- Get Actor Dataでは、Tagでフィルターすることで特定のActorやStaticMeshを取得できます。
- Differenceを使うことで特定の範囲内のポイントを消去できます。
Example03: 特定のStaticMeshの周囲に配置
岩を手動配置して、その周りに花を自動配置する例です。
PCG Graphの全体図です。
岩の周囲にポイントを生成する
まずは岩のアクターの周囲にポイントを生成します。
Example02と同じようにTag指定で岩のActorを取得し、Bounds Modifier
でバウンディングボックスを5倍に拡大します。
Surface SamplerのBounding Shapeに拡大したバウンディングボックスを指定することで、岩の周囲にポイントを生成できます。
ポイントの生成範囲を調整する場合は Bounds Modifier
で5倍の数値を調整します。
Distanceノードで岩からの距離に応じたDensityを設定する
DistanceノードでTargetへのPointの距離を計算できます。
SetDensityをONにして、Maximum Distanceを指定することで、距離から0-1の範囲にDensityを設定できます。
DensityをOneMinusノードで反転してから、Density Filterで中心から離れたポイントを削除します。
Densityの調整
PowやMultiplyでDensityを調整します。
定数ノードの作成
2.0や4.0の定数のノードを作成するには、Create Attributeノードを作成し、TypeをDoubeにし、Double Valueを調整します。
筆者は定数ノードの名前が分からずにしばらく悩みました😱
Static Meshの生成
最後にStatic Mesh SpawnerでStaticMeshを生成します。
Example04: Splineで囲んだ領域内に木を生やす
Splineで囲んだ領域内に木を生やす例です。SplineとPCGを組み合わせるためにはブループリントが必要になります。
PCG Graphの全体図です。
ブループリントの作成
Actorクラスのブループリントを作成します。
ブループリント内にSplineを作成し、Component Tagsに ForestZone
と設定します。
木を生やす目的以外のSplineを使う場合も想定して、Splineの判別用にComponent Tagsを設定しています。
たとえば、道に木を生やしたくない場合、RoadのTagを持ったSpline上にポイントをサンプリングして、 Example02で紹介したDifferenceノードで道にある木を削除するような使い方が可能になります。
次にブループリント内にPCG Componentを作成し、PCG Graphを指定します。
Spline上のポイント生成
Splineの内側にポイント生成します。
まずは Get Spline Data
でブループリント内にあるSplineを取得します。
Actor TagsではなくComponent Tagsでフィルターするために、 Filter By Tag
ノードを使いました。
Component Tagsにした方が1つのActor内に複数のSplineを生成できるので使い勝手が良くなります。
Spline Sampler
でSplineの内部にポイントを生成します。
- Dimention: On Interior(Splineの内側を指定します)
- Unbounded: ON
- Interior Sampling Spacingで密度を調整します
Landscape上へのプロジェクション
Transform Pointsでランダム移動とZ軸上のランダム回転してから、Spline上に生成したポイントを Projection
でランドスケープ上に移動します。
木は上方向に真っ直ぐに生やしたいので、Project Rotations はOFFにしました。
重なりを除去 + StaticMesh生成
Example01でも登場した Bounds Modifier と Self Pruning のコンボ技で重なり合ったポイントを消します。
最後に Static Mesh Spawner でStaticMeshを生成して完了です。
このあたりの処理は定形パターンですね。
まとめ
PCGの基本的なデバッグ方法やよくある処理のパターンを解説しました。
PCGの基本的な処理の流れとしては、ポイントを生成して、Attributeを処理してから、最後にStaticMeshの生成になります。
InspectやDebugを使いながらAttributeの変化を確認すれば、あまり迷わずに使いこなすことができると思います。
StaticMesh上へのポイント生成だったり、複雑なPCGを作成するためにサブグラフ化する方法なども紹介しようと思いましたが、記事が長くなりすぎるので別記事にしたいと思います。
それでは良いPCGライフを!
利用させていただいたAsset
記事のサンプル作成にあたり、以下のアセットを利用させていただきました。ありがとうございます!