ブループリントとPCGで、オブジェクトをプロシージャルに生成&配置。UE5極め本の著者が披露するPCG極め術【UE5 Deep Dive 2023】

2024.01.16
注目記事ゲームづくりの知識しくみをつくる見た目を良くするゲームの舞台裏講演レポートお役立ち情報ツール紹介レベルデザインアンリアルエンジン
この記事をシェア!
Twitter Facebook LINE B!
Twitter Facebook LINE B!

エピック ゲームズ ジャパンが主催する勉強会『UE5 Deep Dive 2023』が、2023年12月15日(金)に開催されました。

Unreal Engine 5で極める!プロシージャル技術』と題した講演では、エピック ゲームズ ジャパン 湊 和久氏が登壇。

プロシージャルにオブジェクトを設置するUnreal Engine 5.2の新機能「Procedural Content Generation」の仕組みや使い方が解説された本講演をレポートします。

TEXT / セレナーデ☆ゆうき

EDIT / 神谷 優斗

目次

登壇者紹介

湊氏は、2023年8月よりエピック ゲームズ ジャパンでソフトウェアエンジニアを務めています。

エピック ゲームズ ジャパン入社前は、ゲーム開発の仕事のかたわら、Unreal Engine 5(以下、UE5)でのゲーム開発入門書『Unreal Engine 5で極めるゲーム開発:サンプルデータと動画で学ぶゲーム制作プロジェクト』の執筆や、ゲームエンジンの開発や数学的背景などを解説する書籍『ゲームエンジンアーキテクチャ 第3版』の日本語版の翻訳監修などにも携わっています。

登壇した湊氏

「プロシージャル」とは?

本講演は、「プロシージャル」という単語の解説からスタート。湊氏は「プロシージャル」を、「『手続き型』を意味する英単語。一定のアルゴリズムに従って、特定のアセット(3Dモデルやアニメーションなど)を自動生成すること(※)」であると説明しました。
※ ゲームメーカーズ 用語集より引用された

「プロシージャル」3つの分類

「ワールドを効率よく構築する」という観点では、プロシージャルを3種類に大別できると湊氏は言います。

1つめは、建物の生成などに使われる3Dモデルの組み立て。2つめは、パラメータからモデルそのものを生成するモデリング。最後に、3Dモデルの配置です。

プロシージャルによる配置では、配置する範囲をスプラインなどで指定する方法もよく用いられる

プロシージャル導入の新たな選択肢となる「PCG」

実際のゲーム開発では、内製エンジンに独自のプロシージャルツールを実装する方法や、Houdiniなどのプロシージャルを得意とするDCCツールでの生成物をエンジンにインポートする方法が使われます。

また、「Houdini Engine(※)」の使用も選択肢のひとつとして挙げられました。
※ Houdiniの計算機能をモジュール化し、ゲームエンジン内に組み込むプラグイン。開発はゲームエディタ上で行いつつ、計算部分はHoudiniの機能を利用できる

「広範囲に木を生やし、森を生成する」などの仕組みをBPと同じように作れる

PCGの根底にある3つの概念

湊氏はここで、PCGの根底にある3つの概念「ポイント」「ボリューム」「アトリビュート」について説明しました。

要素1:ポイント

森を作るため、木のモデルを大量に配置する場合を考えます。

HoudiniやPCGで使われる手法では、地面に「点群ポイントクラウド)」を散布(スキャッター)するアプローチをとります。 散布した点群に対してはノイズ関数で確率密度のばらつきを与え、一定密度以上の点をフィルタリング。残った点にオブジェクトをスポーンすることで、ばらつきのあるオブジェクト配置を行います。

講演では、スプラインメッシュで作られた要塞の中に点群を散布する方法が紹介されました。

スプラインによって区切られた要塞

木をスポーンさせる向きや大きさなどの生成ロジックは、ノードベースの「PCGグラフ」で行います。

PCGグラフの内容。ランドスケープ情報を読み取り、メッシュを配置するまでのロジックが書かれている

PCGグラフで使用するパラメータはアクタに公開できるため、木の数が多いときには配置確率を下げるなどのコントロールが可能です。

同じくランダムで木などを配置するツールには「Foliage」がありますが、再配置には配置範囲の塗り直しが必要です。PCGは、決定済みの範囲内で再生成できる点で優れています。

要素2:ボリューム

木の生成後に、木とは大きさの異なる花をスポーンさせたい場合、木周辺の点はスポーン対象から除外されるべきです。しかし、点の位置情報のみでは、特定の点が木と重なっているかを判定するのは不可能です。

そこで、「ボリューム」を用いて点に体積情報を与えます。

木や花に対応したボリュームの衝突判定を用いることで、花と木の生成を調整できます。

花の点群のうち、木のボリュームと交差する点を除去することで、花と木が重ならずにスポーンできる

将来的にオブジェクトを置きたい場所に空のボリュームを配置した様子

講演では、先ほどの要塞内にボリュームを配置し、内部に木が生えない処理を実装する様子が実演されました。

なお、PCGボリュームは、ワールド上に独立したアクタとして存在するスプラインを利用することができません

そこで、講演ではUEのタグ機能を用いた方法が紹介されました。要塞のアクターにつけたタグに基づいてスプラインを取得し、スプラインの内側にボリュームを配置することで、木の点群との交差判定をとり、除去しています。

スプラインに「fortress」のタグをつけ、認識させている

要素3:アトリビュート

各点は、位置以外にも確率密度やボリュームなどの情報を含んでいます。これらの情報は「アトリビュート」と呼ばれ、開発者側が自由に追加し、運用できます。

例えば、川の近くの石は河口からの距離に比例して大きくなります。そこで、河口からの距離を点がアトリビュートとして保持することで、メッシュの大きさに反映できます。

要塞と森の例では、要塞からの距離を「distance」アトリビュートとして保持させ、一定以上離れている点をフィルターした

生成物の「カプセル化」

下記画像における街路樹は、レンガや落ち葉、樹木などから構成されています。

これらをプロシージャルに配置する場合、1つの街路樹を複数のオブジェクトから構成された複合的なオブジェクトとみなすことができます。複合的なオブジェクトとしてとらえることは「カプセル化」と呼ばれます。

講演では、PCGにおけるカプセル化の方法として「アセンブリ」と「Construction Script(※)」の2つが紹介されました。
※ 各アクタが構築時に実行する関数

アセンブリは、点群情報をアセット化する手法です。新たに散布した点それぞれにアセット化した点群を配置することで、一連の巨大な点群を作成できます。

Construction Scriptを用いる手法では、配置はPCGが、形状の構築はConstruction Scriptが担うといった分業が可能です。

アセンブリを行う方法

アセンブリには、手作業で作成されたコンテンツが必要です。

手作業でレベルに配置されたコンテンツを選択し、レベルアセットとして書き出します。

アセットの生成時には、原点を指定できる

生成した点群アセットは、PCGグラフにドラッグ&ドロップすることで、点群を出力するノードとして使用できます。

点群情報から配置するメッシュを選択する場合は「Mesh Selector Type」オプションを使用する

ソースとなるレベルデータのアクタにタグをつけることで、配置にバリエーションを持たせることもも可能

Construction ScriptつきアクタをPCGで配置する

Construction Scriptを用いる手法では、スタティックメッシュではなく、Construction Scriptを実装したアクタをスポーンさせます。PCGにおけるアクタのスポーンには、「Spawn Actor」ノードを使用します。

アトリビュートの値をアクタのプロパティに書き込む機能「Actor Overrides」も用意されている

講演では、「Height」プロパティを基にConstruction Scriptで高さを決定する塔のアクタを配置する実演が行われました。

PCGグラフでは、ランダムな「BoundsMax」アトリビュートを持つ点を散布します。そして、Spawn Actorで塔のアクタを生成する際に、「Height」プロパティを各点が持つ「BoundsMax」アトリビュートでオーバーライドします。

これにより、スポーンされるアクタのHeightプロパティにばらつきを与えられます。

ただし、Construction Scriptの実行後、アクタのスケールは点のScale値で上書きされる点には注意が必要とのこと

PCGと「World Partition」を併用するテクニック

PCGコンポーネントの「Is Partitioned」オプションを有効化することで、UE5のレベルストリーミング機能「World Partition」に対応します。

「木を管理するグリッドは小さくていいけど、塔のグリッドは大きく扱いたい」など、ボリューム感の異なるコンテンツを1つのPCGグラフで扱う場合は、「Hierarchical Generation」機能を有効化します。

この機能によって使用できるようになる「Grid Size」ノードによって、ストリーミングのグリッドサイズをグラフから制御することが可能になります。

Use Hierarchical Generationオプションにチェックを入れると、Hierarchical Generationが有効化される

Hierarchical Generationを使う際にPCGWorldActor配下に生成される「PCGPartitionActor」は、PCGグラフの実行にあたり、対応するグリッドサイズに属するノードネットワークのみを稼働させます。また、実行時は大きなグリッドサイズのPCGPartitionActorから順に実行されます。

なお、Grid Sizeを導入した時点でグリッドサイズに対応した親子関係が生じ、自身より小さいサイズの生成物に依存した処理を行えなくなる点には注意が必要です。

最適化のため、自身より大きなグリッドサイズの生成物を参照する場合はキャッシュを利用する

また、Hierarchical GenerationはConstruction Scriptのあるアクタの生成にも対応しており、HLODの構築も可能です。

 HLODに対応させるには、Mobility(可動性)をStaticにする必要がある

BPでPCG用ノードを自作する

PCGグラフにおけるノードは「PCG Element」と呼ばれ、C++BPを用いて独自に実装できます

PCGプラグインのフォルダには、BPで作られたPCG Elementがいくつか格納されている

BPでPCG Elementを実装する際は、「PCGBlueprintElement」を親クラスに指定します。そして、ノード実行時の処理にあたる「ExecuteWithContext」関数をオーバーライドすることで、独自の処理を実装できます。

PCGグラフ上でのメニューにノードを表示させる場合は、「Expose to Library」オプションを有効化します。なお、表示させずとも、コンテンツブラウザからドラッグ&ドロップすることでノードを配置できます。

PCGにおける入力データの特性

ノードの入出力ピンは、「Input」および「Output」オプションからカスタマイズ可能です。

各ピンは、ラベル(ピンの名前)とType(型)の情報を持ちます。TypeをAnyにすると任意の型を受け付け、PointやSplineなどの型を指定すると受け付ける型を限定できます。

また、PCGにおけるワイヤーは、一度に複数の点群情報が入力されるマルチデータの仕様になっています。

「Multi Connection」を有効化すると、複数ワイヤーの接続を許可するようになる。そもそもマルチデータを許可しない場合は「Allow Multipule Data」を無効化する

BPで実装されるPCG Elementでは、オプションで指定した入力ピンの数に関係なく、基本的にノードで表示されるピンは1つのみです。そのため、1つの入力ピンから処理に使用するデータを抽出する必要があります。

講演では、「任意のデータが単一の入力として扱われる」PCGグラフの概念が図示されました。

実際に入力されるデータは、すべてのデータをラップした「PCG Data Collection」構造体です。この構造体は、点群のデータ(Point Data)やスプラインのデータなどをひとまとめにしたデータの配列を持っています。

Point Dataは、メタデータと、実際の点の配列を持ちます。そして、配列中の点のデータは、位置情報や大きさなど基本のアトリビュートとして扱われるプロパティを保持。開発者が任意で追加するアトリビュートは、メタデータとの組み合わせで保持されます。

実際にPCG Data Collectionから目的のデータを取得するには、指定したラベル名と一致するデータを検索する「Get Typed Inputs by Pin Label」などの関数を使用します。

マルチデータの入力では、ピンから取得できるデータが複数あるため、処理を複数回行うために「For Each Loop」ノードを利用します。

さらに、点群データから点のデータを1つずつ取り出すのにも「For Each Loop」が必要となるため、必然的にネストループ(ループ内ループ)の構造になります。

出力データで気を付けるべきポイント

PCG Elementから結果を出力するには、出力用のデータ配列を作成する必要があります。

入力に使われたPoint Dataは、出力には使ってはいけないルールがあるため、出力用のコンテナとしてPoint Dataを新たに構築しなくてはいけません。

メタデータやアトリビュートを入力データから出力データへ正しく継承する場合は、「Initialize from Data」ノードを使います。

単なるコピーでは正しくデータを渡せないため、「Initialize from Data」を使う必要がある

新たに作成した出力用のPoint Dataには、処理結果となるポイントの配列をセットします。これをPCG Data Collectionにセットし、リターンノードから出力します。

なお、通常の入出力ピン以外にピンを追加する場合は、Custom InputやCustom Outputが利用できます。

変数を公開すると、ノード上に公開されるようになる

実演:塔の生成上限を設定

ここで、先ほど実演した塔の生成に対し、分布密度や確率密度ではなく「領域内に最大10か所」といった条件付けを行う方法が紹介されました。

作成するのは、入力で指定した個数のポイントをランダムで選択、Outから出力するノードです。

ノード実装の様子。選ばれなかった点はOthersから出力させている(なお、この実装にはスライドの後半で解説される『決定論』的な問題があり、対応方法もそこで説明されている。詳しくは文末で紹介するスライド資料を参照)

PCG Elementでループ処理を実装するには

ループ処理実装のフレームワーク

Point Dataに格納されたポイントをループ処理するケースでは、「For Each Loop」の代わりに「Point Loop」ノードが使えます。

Point Loopノードは、自身の「Point Loop Body関数を呼び出して実行します。そのため、ループ処理の実体はPoint Loop Bodyをオーバーライドして実装します。

Point Loop Bodyで出力されるデータは自動的に1つのPoint Dataに集約されるため、そのままPCG Elementの出力として使用できる利点があります。

実演:塔の位置をオフセットする

次に、ボリュームの底の高さを座標点まで引き上げるアンジュレーションを行うノードの実装が実演されました。

アンジュレーションノードの実装。Execute With Contextで塔を設定し、底部を表面まで引き上げる処理をオーバーライドしたPoint Loop Bodyに実装する

ノードの実行結果

ループ処理における3つの重要ポイント

ここで、湊氏からループ処理における重要なポイントが3つ紹介されました。

1つめは、Point Loop Bodyにおいて戻り値として点を返すかどうかは、Return Valueにチェックをつけることで制御できる点。また、関数呼び出しはConst関数に限られる点です。

Const」オプションにチェックを入れていない関数を使うとエラー扱いになる

2つめは、点のメンバ変数を書き換える場合には、「Set members in PCGPoint」ノードを使う必要がある点です。

点のメンバ変数を取得する場合はBreakするだけでよい

最後に、Set members in PCGPointでは、点のデータを参照形式で取得・出力する点です。

出力用ポイントを作るために入力ポイントを加工してしまった場合、想定と違う挙動になる可能性があります。そのため、「Copy Point」ノードで入力のコピーを取ってから加工することを湊氏は推奨しています。

また、PCG Elementに用意されている「Iteration Loop」や「Nested Loop」関数には、自動で非同期処理されるため利用するメリットがあることも紹介されました。

Iteration Loopは指定した数のループを実行、Nested Loopは2つのPoint Data間で入れ子のループを実行する

実演:スプラインの再生成

3Dモデルの横幅に等しい距離で点を打ったスプラインに、モデルを配置するシチュエーションを考えます。

アセットのピボットがセンターになっている場合、打った点の始点と終点を越えて配置され、スプラインの範囲よりも広い範囲にメッシュが配置されます。

点の端から、フェンスがはみ出てしまっている

こういった問題には、スプラインから読み取った2点の中間点に点を置きなおすアプローチが考えられます。

本来はC++でスプラインサンプラーを実装する必要がありますが、独自のPCG Elementを用いることで、BPのみで同様の処理が実現可能です。

本来はここでデモを行う予定でしたが、講演の終了時間が迫ってしまいました。

公開された資料では、さらなるPCG Elementの発展としてアトリビュートの読み書き方法や、決定論非同期処理の対応方法などの解説も行われています。

以降の詳細は、スライド資料をご確認ください。

『Unreal Engine 5で極める!プロシージャル技術』スライド資料UE5 Deep Dive 2023
セレナーデ☆ゆうき

ゲームのタイムアタックを中心に、ストリーミングサイト・Twitchで活動をしているストリーマー。ゲームイベントの紹介記事など、WEBメディアでの活動実績もあるが、繰り出されるダジャレのクオリティには賛否両論がある。

https://www.twitch.tv/serenade_yuuki

関連記事

クロスシミュレーションツール「Marvelous Designer」が1年間無料で使用可能。Epic Games、UEFNクリエイターに向けてライセンスを期間限定で提供中
2024.06.25
mocopiのモーションデータをリアルタイムでMayaに送れる公式プラグインが公開。併せて、UE版プラグインがUE5.4に対応
2024.06.21
UEでローカルLLMを実装するプラグイン、「技術書典16」でUE技術書を販売した挑戦の記録など。技術勉強会「UE Tokyo .dev #3」の講演資料が公開
2024.06.19
Epic Games、UEとUEFNにおけるオーディオ技術の紹介記事を公開。メタバースのサウンド構築に使える「MetaSounds」、音楽制作ツールセット「Patchwork」なども解説
2024.06.18
500以上のアニメーションを同梱。UE5.4の「Motion Matching」学習に役立つサンプルプロジェクトをEpic Gamesが無料公開
2024.06.13
「Unreal Engine」2024年6月の無料マーケットプレイスコンテンツが公開!バイキングの家をイメージしたアセットや、インベントリを実現するブループリントアセットなど
2024.06.05

注目記事ランキング

2024.06.19 - 2024.06.26
VIEW MORE

連載・特集ピックアップ

イベントカレンダー

VIEW MORE

今日の用語

ワイヤーフレーム(Wire Frame)
ワイヤーフレーム
  1. 3Dモデルのエッジ情報のみを表示するレンダリング手法。ゲーム開発においては、3Dモデルやシーンのポリゴン構造を確認することに用いることが多い。
  2. UIやWebページなどのレイアウトを決めるための設計図。
VIEW MORE

Twitterで最新情報を
チェック!