ケンケンパで学ぶPCG Shape Grammarの基本

PCGを使用すると、地面にポイントを散布して属性をつけ、ランダムに木や岩を配置することが簡単に実現できます。また、スプラインを引いてスプライン上をポイントでサンプルし、単一のアセット(街灯やコーンなど)を並べることも容易です。

一方、線上に並んだポイント群に自由な規則で物を置こうとすると、案外苦戦します。たとえば、スプライン上に子どものころ遊んだ「ケンケンパ」を

ケン・ケン・パッ・パッ・ケン・パッ・パッ
ケン・パッ・ケン・パッ・ケン・パッ・パッ

のように並べたいとします。PCGの基礎機能でこれを行おうとすると、先頭のポインからインデックスを見て「ケン」か「パ」に割り振るロジックを組む必要があり、意外と一筋縄ではいきません。上記のケンケンパの並び”だけ”に特化したグラフなら比較的簡単に組めますが、別の並び(ケン・パッ・パッ・パッ・パッなど)に変えたくなった場合に、グラフの大幅な変更が必要になります。

こうした課題では、UE5.5から導入された「Grammar」機能が非常に役に立ちます。Grammarを使えば、アセットの並びを、

[Ken, Ken, Pa, Pa, Ken, Pa, Pa
Ken, Pa, Ken, Pa, Ken, Pa, Pa]*

のように文字列で直感的に記述できるようになります。別の並びへの変更も、与える文字列を [Ken, Pa, Pa, Pa, Pa]* のように書き直すだけで実現できます。

フェンスから建物まで応用範囲が広い本格的な技術ですが、本記事では「ケンケンパ」という単純な課題を通じてPCG Grammarの基本的な使い方と基礎的な挙動を確認します。

使用したUnreal Engineのバージョンは5.7.1、インターフェイスは英語となります。

PCGが初めての方は、先に Epic Games Japan のPCG入門スライドなどをご覧ください。

準備

解説に先立ち、Unreal Editorのモデリングモードを使用して、SM_KenとSM_Paという2種類のスタティックメッシュを自作しました。半径50、高さ20のシリンダーを、半径40のシリンダーでくりぬいて輪っかにしたもので、ピボットは中央に置いてあります。

形状まで真似る必要はありませんが、テストのために奥行き(X軸の幅)が100ユニットのメッシュを2種類準備するとよいと思います。

プロジェクトの作成

  1. 新しいプロジェクトをBlankテンプレートで作成します

  2. プラグインで「Procedural Content Generation Framework (PCG)」を有効にします。

  3. File > New Level > Basic で新しいレベルを作成し、保存しておきます。

PCGブループリントクラスの準備

  1. 新しいブループリントクラスを「Actor」クラス継承で作成し、「BP_KenKenPa」などと名付けます。

  2. BPエディタを開き、[DefaultSceneRoot]の下に[Spline]コンポーネントを、さらに[PCG]コンポーネントを追加します。

  1. レベルエディタに戻り、このBPクラスをレベル上に配置します。

  2. スプラインを適度に延伸(先頭のポイントをAlt +左ドラッグ)します。

PCGグラフを作成する

  1. コンテンツブラウザから空のPCGグラフを作成し、「PCG_KenKenPa」などと名付けます。

  2. 作成したPCGグラフを、レベル上に置いたBPクラスのPCGコンポーネントにセットします。

  3. PCGグラフを開いて、下図のようにノードを配置します。

このグラフ構成は、Get Spline Dataノードで取得したスプラインデータを、Subdivide Splineノードでポイントに分割することを意図しています。

Grammarを使用する

Subdivide Splineは、Grammar機能を利用できるノードのひとつであり、設定された「モジュール情報」に基づき、スプラインをポイントへ分割します。ひとつひとつのモジュールは、主に名称(Symbol)とサイズ(Size)で構成されます。Subdivide Splineは、与えられたスプラインの線上を、これらの様々なサイズのモジュールをはめこむことで埋め尽くせるように、分割の計画を立ててくれます。

初めに、Subdivide Spline ノードでモジュール情報(Modules Info)を定義します。詳細パネルでModules Info横の+ボタンを2回クリックして、下図のように設定しましょう。

モジュールの名前はそれぞれ「Ken」と「Pa」で100UU(1メートル)の長さを持ちます。視覚化のために、Debug Colorを赤と緑にしました。

ただし、これらのモジュール設定では、適当に引いたスプラインを余白なくピッタリ埋めつくすことが難しい(余白が生じやすい)ため、エラーが出る場合があります。このエラーを解消するには、

  • モジュールのScalableにチェックを入れて(=拡大縮小を許可して)、スプラインをきっちり埋めつくせるようにする。もしくは、

  • [Accept Incomplete Subdivision]にチェックを入れてスプラインに余白が残ることを容認する

のうち、どちらかの方法を取ります。

モジュール情報の準備が終わったら、スプラインを「ケン・ケン・パッ」の繰り返しで分割するよう、Grammar Sgtringに [Ken, Ken, Pa]* という文字列を与えます。

image

この正規表現のような文法の詳しくは後ほどマニュアルを紹介しますが、基本的には、

  • [ ] 内はパターン

  • * はスプラインが続く限りパターンの繰り返しを指示する修飾子

となります。ノード上で d キーを押してデバッグをONにし、レベルエディタに戻って表示を確認してみましょう。

上図のように、スプライン上にフェンスっぽいものが敷かれていれば、うまく動作しています。

モジュールの高さ

デバッグ表示時のメッシュの「高さ」は、Subdivide Splineノードの「Module Height」プロパティで制御されますが、位置について注意点があります。 Subdivide Splineは、モジュールの中央にピボットがある前提でポイントを配置するため、PCGグラフノードにデフォルトで設定されているデバッグ表示用メッシュ「PCG_Cube」のような底部にピボットでは、ポイントより少し浮いたところからデバッグ表示が始まります。

より正確なプレビューを得るために、100x100x100で中央ピボットのスタティックメッシュを別途用意して使用することをお勧めします。

デバッグ表示の色分け

このままですと「ケン・ケン・パ」の切り分けが期待通り機能しているか分かりづらいので、上で設定した Debug Color に基づき、色分けを試みます。これを行うには、モジュール情報にあるDebug Colorを分割ポイントに渡して、何らかの手段で視覚化につなげる必要があります。

まず初めに、PCGグラフに戻り、Subdivide SplineノードのExtra Output Attributes > Debug Color Attribute Nameにチェックを入れます。これにより、Modules Info で定義したDebug Color が指定した名前の属性(ここでは「DebugColor」)で、分割ポイントの属性に追加されるようになります。

この重要な動作を確認しておきましょう。Subdivide Spline ノードで a キーを押し、Attributesパネルで入出力情報を見られるようにしてから、プルダウンで情報を “Output” のものに切り替えます。すると下図のように、

  • 「Symbol」列で各ポイントがパターンに基づいて KenとPaに振り分けられていること、

  • KenにはKenのDebug Colorが、PaにはPaのDebug Colorが割り当てられたこと

が確認できます。

これは、Grammar文字列とモジュール情報に基づいてスプラインをポイントに分割する際に、モジュール情報に付属する属性を、分割ポイントの属性に追記できることを意味します。つまり、モジュール情報を拡張すれば、それを分割ポイントの属性経由で後で取り出せるようになるわけです。この挙動は、Grammer機能を使いこなす上で、非常に大きなキーポイントとなります。

それでは、改めて、色分けの実装を行いましょう。この DebugColor 属性を視覚化する方法はいくつかありますが、今回は標準属性の「Color」にコピーして利用する方法を採用します。

  1. Subdivide Spline ノードの右側に Copy Attributes ノードを配置します

  2. Target と Source 両方に Subdivide Spile の出力を接続します

  3. Copy Attributes ノードの Input Sourceに「DebugColor」、Output Targetに「$Color」を指定します。

  4. Copy Attributes ノード上で d キーを押し、デバッグ表示に切り替えます

  5. デフォルトのデバッグ表示は、Colorに設定した色を参照しないため、Debug > Material Override プロパティの右側に表示されている「Color」ボタンをクリックして、マテリアルを切り替えます

これで最低限の色分けが実現できますが、「ケン・ケン」のように同色が続く箇所で、個数を正確に把握することが困難です。間隔をとるために、 Bounds Modifilerノードを追加接続し、X軸を縮めることをお勧めします。

Bounds Modifier ノードでも「Color」ボタンを使い、デバッグ表示用マテリアルを変更します。今後はこのノードをデバッグ用に使用するとよいでしょう。

あとは、Attribute FilterノードでSymbol属性をフィルタリングし、KenとPaでメッシュをスポーンし分ければケンケンパのPCGが完成しますが、本記事ではこの作業を行わず、より高度な方法でメッシュの出し分けを行います。

Grammar をパラメータ化する

まず、Grammarの文字列をグラフ内で決め打ちするのではなく、レベルエディタ上から打ち込めるよう、グラフパラメータ化を行います。

初めに、PCGグラフに戻り、Subdivide Spline ノードの[Grammar as Attribute]プロパティにチェックを入れます。この操作により、グラマーの文字列をプロパティの決め打ちではなく、ポイントの属性から拾うようになります。属性名を指定することも可能です。

左下のParametersパネルで「文字列」(String)型のグラフパラメータを追加して「Grammar」などと名付け、デフォルト値におなじみの [Ken, Ken, Pa]* をひとまず入れておきます。

そして、Get Spline Data と Subdivide Spline ノードの間に Add Attribute ノードを挿入し、上図のように組み立てます。この組み立てにより、グラフパラメータの文字列が属性としてスプラインデータに追加され、一緒にSubdivide Splineノードに流し込まれます。

※補足:Subdivide Spline ノードはデフォルトで @Last の属性(=最後に追加された属性)を Grammar 文字列として拾います。属性名を明示したい場合は、Add Attribute のOutput Targetと、Subdivide SplineのGrammar Attributeを合わせてください。

レベルエディタに戻り、PCGコンポーネントの配置したPCGアクタの Parameters Overrides プロパティから Grammar を指定できるようになるので、ケン・ケン・パの内容を書き換えてみましょう。

使用するメッシュをパラメータ化する

「Ken」と「Pa」でメッシュを出しわけるにあたり、上述した Attribute Filter を使うやり方では応用が利きませんので、ここからはスタティックメッシュアセットの配列を使用してパラメトリックに指定する手法を紹介します。

先に述べたように、Subdivide Splineにはモジュール情報側の属性を(出力の)分割ポイントの属性に追記する機能があります。ただし、Subdivide Spline内でモジュール情報を編集する限り、モジュール情報に追加の属性を持たせることはできません。そこで、モジュール情報をパラメータ化し、Add Attributesで追加の属性を持たせる(ここにメッシュ情報を書いておく)ことで、最終的に「Static Mesh Spawner」で属性に基づくメッシュの出し分けを行うようにします。

初めに、PCGグラフに戻り、「PCGSubdivision Submodule」型のパラメータを”配列”として作成して「ModulesInfo」などと名付けます。そのデフォルト値には、以前 Subdivide Spline の Modules Infoプロパティで設定したものと同じ値を定義します。

続いて、この2つのモジュール情報に対応するメッシュ情報も、グラフパラメータとして用意します。「Static Mesh」のObject Reference型のパラメータを”配列”として作成して、「MeshInfo」などと名付け、ModulesInfoと同数のアセットをデフォルト値として登録します。この記事ではSM_KenとSM_Paを登録しましたが、テストできるならどんなスタティックアセットでも構いません。

2つのパラメータの準備ができましたので、Add Atributeノードを使用して、Modules InfoにMesh Infoの内容を「Mesh」属性として追記するように組み上げます。

次に、Subdivide Spline ノードの Modules Info as Input とForward Attributes from Modules Infoにチェックを入れ、 Modules Info ピンに Add Attribute の出力を接続します。

  • Modules Info as Input: ノードのプロパティにモジュール情報を埋め込むのではなく、外部からパラメータとして取り込むためのフラグです。

  • Forward Attributes from Modules Info: Modules Infoに含まれる非標準の属性も Symbol や Debug Color と同様に出力の分割ポイントの属性に追記されるようになります。

最後に、Subdivide Splineノードに(既存のノードとは別路線として)Statch Mesh Spawnerを追加し、Mesh Selector Typeに「PCGMeshSelectorByAttribute」を、Attribute Nameに「Mesh」に指定すれば、パラメトリックなメッシュの出し分けが完成します。

以上が、簡単ではありますが、PCG Shape Grammarの基本的な使い方の説明となります。またの機会があれば、Grammarを使用したフェンスや建物の作成方法もご紹介したいと思います。

下がこの作業の完成画像となります。メッシュの高さが20ですので、Module Heightを「20」に変更しています。

参考資料

1 Like