- はじめに
- 前提
- PCG(Procedural Content Generation Framework)
- PCG始動
- 草を生やそう
- PCG原理
- 点の中身について
- グラフパラメータについて
- 余談
- 終わり
はじめに
こんにちは、クライアントエンジニアの下野です。
今回から何回かに分けて、PCGについて解説とかいろいろをやっていきます。
前提
エンジンのバージョンは5.7です。バージョンによっては処理が変わったりするので完全に処理を一致させても動かない場合があります。
PCGはUE5.7になってBetaからProduction-Readyになったので、以降のバージョンで破壊的変更は無いはずですが、過去バージョンを使う際は注意してください。
PCG(Procedural Content Generation Framework)
背景物やアセットを自前のルールに則って生成するツールです。
木々や建物の配置を1つ1つ考えていると大変なので、建物同士の間隔をどの程度空けるか、道路の範囲には木や建物を生やさないなどの生成ルールを作ることで、自動でアセットの配置をしてくれます。
パラメータの調整で、反映や更新も即座にできるので、レベルデザインの効率が上がる便利機能です。
記事一覧
第一回(今回) tech.spark-creative.co.jp
PCG始動
PCGを使う場合は、プラグインを有効にする必要があります。
UE5.7になってPCGバイオームとか新しいBeta機能が増えましたが、今回はPCGFramework一個で十分です。

チェック入れて再起動したら使えるようになります。
草を生やそう
先に処理を作って、後から解説を入れていきます。
まずはコンテンツブラウザからPCG→PCGグラフで新規の空のグラフを作成します。


作成したグラフをクリックするとエディターが開くので、一旦以下のようにノードを繋いでいきます。

Static Mesh Spawnerを選択するとインスペクターに色々出るため、Mesh Entriesの+ボタンを押し、StaticMeshに生成したいメッシュを入れます。

次に、レベル上にPCGボリュームを配置します。
現状のノードの配置では、メッシュに対してメッシュを生やすことができないので、ランドスケープを配置してください。
BPを作成しない場合は、レベル上からPCGボリュームを追加すると早いです。

Volumeのサイズを適切に広げ、PCGComponent内のGraphに先ほど作成したPCGグラフを設定します。

BPから生成とか再生もできるので、動的に地形が変わる場合の対応も取れますが、今回は特に使用しません。

正しくノードを繋げていたら、生成のボタンを押すことで先ほど設定したメッシュが生えます。

では、解説を入れていきます。
PCG原理
PCGのP (Procedural) の部分、手続きについてです。
PCGはメッシュを生やすためにいくつかの手順を踏みます。
その手順が先ほど作成したグラフ、各種ノード(PCGではエレメントと呼ぶ)で行われるので順番に解説をしていきます。
グラフのInputとOutputはグラフを関数化したりした際に使うもので、今回は無くても動く+以降触る予定なので省略します。

サンプリング
メッシュを生やせる地点を検索し、点を散らします。
PCGでは、地形に即メッシュを配置するのではなく先に点を散らし、移動や回転、どんなメッシュを置くか、不要な点を削除するかなどの情報をエレメントで設定してから、最後に残った点の情報を使いメッシュを生成します。
そのための第一段階、点を撒くためのエレメントがSurface Samplerです。

PCGFrameworkのプラグインしか設定していない場合は、Meshから点を生やすエレメントは無く、追加でPCGGeometryScriptInteropプラグインを有効にするとStaticMeshなどから点を生やせるMesh Samplerが追加されます。
デバッグ
エレメントの説明だけでは、実際に何が起きているのか分かりづらいという節があります。
そのため先に便利なデバッグ機能のお話をします。
エレメントを選択した状態でDキー、もしくはエレメントを選択した際に出るインスペクターからデバッグという項目を探し有効にします。

するとエレメントの左上に青い丸が出てきます。

この状態では、青マルがついたエレメントまでの処理をして、その時点で存在する点の位置にデバッグのCubeを生成してくれます。
今回はSurface Samplerにこれを適用したので、メッシュの生成されている位置にCubeが生えていることがわかります。

本来はどこまで正しく動いているかのデバッグ用だと思うので、自由に活用して下さい。
メッシュの生成
散らした点の位置にメッシュを生やすにはStatic Mesh Spawnerを使います。
Actorを生やせるエレメントもありますが、負荷を考えるならInstanceStaticMeshとして生やせるMesh Spawnerが一番いいと思います。

Mesh Spawnerを選択して、インスペクターを見ると生成するコンポーネントやメッシュ、マテリアルなど様々な情報を指定できます。

ここまでを正しく設定出来たら、ランドスケープ上に草が生やせます。
Mesh Entriesは配列なので、複数メッシュを登録することでランダムで別のメッシュをはやすことも出来ます。

今回はサンプリングしてメッシュ生成するという単純な機能しかありませんが、Transform Points を使用した回転・拡縮や独自のエレメントを使って点を間引いたり、様々な処理が可能です。
次回やる予定なので割愛します。
点の中身について
さて、ここまででグラフとエレメントの基本的な仕様を解説してきましたが、点群はどのように情報を保持しているのでしょうか。
先ほどまで行ってきた移動・回転・拡縮・密度のような様々な情報がどう入っていて、どのように処理されるのかについて解説していきます。
プロパティ
点が個別に持っている情報群です。
エレメントをダブルクリックするか、選択した状態でAキーを押すと黄色い丸が出ます。

この状態でエディターの画面下部に属性のタブが出ます。

これが、黄色い点があるエレメント処理後の点群の情報になります。
PositionやRotationなどのほかにDensityなどがあります。
Densityは密度という意味で、Density Filterノードを使用すると密集した点を間引くことができます。
Density Filterなど一部のエレメントは内部でこの値を使用しているので調べてみるのも面白いです。
Surface SamplerとMeshSpawnerの間にエレメントを入れるとこのような感じで大方消えます。

さて、プロパティだけでも色々な状況に対応できますが、建物との距離を取ったりよりコアなことをするには持っている情報が少なすぎます。
そのため、自分で好きな変数を追加したいところですが、プロパティはエンジンで使う変数群だからか追加や変更が出来ません。
独自の変数を使用したい場合には、アトリビュートというものを使用します。
アトリビュート
役割はプロパティと同じですが、ユーザーが独自に変数を定義できるのがメリットです。

アトリビュートの追加はAdd AttributeやAttribute Noiseを使います。
オブジェクト間の距離やメッシュなど、処理に応じた値を入れるならAdd Attribute で、なんでもいいから適当な値で埋めるならAttribute Noise という使い分けをします。

今回はAdd AttributeでTestという名前でfloatの0を入れるようにしてみました。

Aキーを押して属性タブを見ると、点の末尾にTestというものが追加されていることがわかります。

このTestを使うには、Filter Attribute Elementsなどを使用します。

演算子で比較したり一致してるかを確認できます。
ターゲット属性としきい値属性にアトリビュート名を入れることで比較ができます。
プロパティをここで使う場合は$プロパティ名のように、最初に$を入れます。

条件に合った点はInside Filterに入り、合わなかったものはOutside Filterに入ります。
あとは残った点を使ってメッシュを生やせば完成です。
グラフパラメータについて
先ほどまでの例ではMesh Spawnerに直接メッシュを格納していますがこれには問題があります。
処理を変えずにメッシュだけ変えたい場合に、エレメントの中身が違うだけで、同じ内容のグラフが2つ出来てしまい、アセット数が無駄に増加してしまいます。
グラフは変えずに中身のメッシュだけ後から変更できるようにしたい、
このような状況に対応できるのがグラフパラメータです。エディターの左下にあります。

+ボタンから変数を追加可能で、BPに公開されている型は大体なんでも入り、配列化も可能です。

今回はMeshを変更できるようにしたいので、型はStaticMeshを使用します。

使用する際は変数名を検索にかけたらエレメントを出せるので、エレメントの入力にしたり点にアトリビュートとして突っ込んだりします。

今回はAdd Attributeを使い、Testのアトリビュートにメッシュを突っ込みます。

見づらいですが、正しく設定出来たらTestの中にアセットの参照が入ります。

Mesh Sampler内でアトリビュートを使うには、Mesh SpawnerのメッシュセレクタタイプをPCGMeshSelectorByAttributeに変更して、アトリビュート名をセットしてあげないと機能しないので注意してください。

追加したものはPCGグラフのParameterOverrideの項目から手軽に変更可能です。

余談
おまけです。
PCGグラフを作るのが面倒とか、とにかく簡単に触ってみたいなどあると思います。
そんな皆様のために、プリセットから簡単にメッシュを生やせる機能が備わっています。
まず、モードからPCGを選択します。

画面左にPCGのウィンドウが出るので、PaintからPlaceToolを選択します。
StaticMeshesの+ボタンを押し、生成したいStaticMeshを選択します。

この状態でビューにカーソルを持っていくと赤マルが出るので、クリックしたらその位置にメッシュが生えます。


使用するグラフを変更したり、ボリュームやスプラインなど別の機能に変えることで、UE内で既に実装されているグラフからメッシュを生成することが出来ます。
終わり
いかがでしたか?
この記事本当はUE5.8のPreviewが出るより前に出そうと思ってたのですが、気づけばもうリリースしてました。
残りの記事を出し終えるまでに5.8が出てしまいそうです。
今回はグラフの基礎的なことについて解説を行ったので、次回はよく使うエレメントの解説や、独自エレメントの作成方法について深堀りしていきたいと思います。