Out-of-core precompute:
Enlighten 3.10 supports development for massive world

2020年8月5日

イントロダクション

2019年11月、Enlightenチームは最新SDKとしてバージョン3.10をリリースしました。シリコンスタジオに移ってから初めてのリリースであり、開発には長い期間を要しましたが、その甲斐あって単なるバグフィックスだけではなく様々な有益な機能の追加も行うことができました。各種アップデートの詳細についてはリリースノート(SDK/UE4)を確認していただきたいのですが、本記事ではその中でも目玉機能の一つであるUE4での『Out-of-core precompute』についてご紹介していきたいと思います。

はじめにこの機能がなぜ必要なのかという点について簡単に説明をして、それからこの機能の技術的な詳細について少し掘り下げてお話したいと思います。そこから実際のスクリーンショットを交えながらどのようにこの機能を使用するのかをお見せいたします。

背景

昨今ではマシンパワーの増大などもあり、ゲームの中で多様な体験ができるようになりました。AAAクラスのゲームでは、よりリッチな体験や高い没入感を実現するため、プレイヤーが動き回ることのできるシーンの規模はますます大きくなっています。広大な世界を構築しようとすると、開発者は数多くの困難に直面します。その中でもアセットの準備にかかる工数というのは頭の痛い問題ではないでしょうか。アーティストがモデリングなどで手を動かす時間が増えるのは言うまでもなく、そこから最終的にゲームで必要となるデータを構築するためにそれぞれのアセットに対して様々な処理を行う必要があるため、実際の物量の増加は想像以上になることがほとんどです。

サードパーティ製のミドルウェアやツールなどを使っていたらアセットに対して実行する必要のある処理は更に多くなります。Enlightenも例外ではなく、ランタイムで効率よくグローバルイルミネーションを計算するために、事前にシーンを処理する必要があります(Precompute)。当然ではありますが、EnlightenのPrecomputeはシーンが広くなればなるほど、処理にかかる時間は増えてしまいます。Incredibuildを活用しビルドファームをスケールすることによって問題を軽減することは可能ですが、シーンの規模が著しく大きい場合、計算に膨大なメモリが必要となり各タスク自体に時間が非常にかかってしまうようになります。そうなるとEnlightenのPrecomputeが大きなボトルネックとなってしまい開発のワークフローが正常に機能しなくなってしまいます。先に述べたようにゲーム空間がどんどん大きくなっている今、大規模なシーンを構築する場合でも効率的に作業ができるようにEnlightenを改良する必要がありました。

そこで私たちはEnlighten 3.10において、Out-of-core precomputeを導入することでこの問題の解決に取り組みました。この機能によってEnlightenは広大なシーンを効率的に処理できるようになったのです。

技術詳細

広大なシーンの管理について

このセクションでは一般的なレベルのストリーミングについて簡単に説明します。既にこのトピックについて詳しい人は読み飛ばして、次に進んでいただいて構いません。

ゲームで広大なシーンを扱うとき、そこに存在するすべてのオブジェクトを常に取り扱えるようにしておくことはできません。なぜなら大量のメモリや膨大な処理が必要となり、現在のハードウェアではすぐにリソースを使い切ってしまうからです。通常、このようなケースではシーンを細かい単位に分割し、ゲームの実行中に必要に応じてその一部を読み込んだり破棄したりすることで問題を回避します。一般的にこの手法をレベルストリーミングといいます。

※図はWorld Composition User Guideより引用

※図はWorld Composition User Guideより引用

この手法の基本的な考え方としては、プレイヤー座標から一定範囲内に存在するレベルのみを読み込むといったものになります。例えば、下図①のように座標Aにプレイヤーがいる場合は、その周囲のレベルが読み込まれています。そこから座標Bに向かって移動を行うと、進行方向にあるレベルが新しくレベルが読み込まれる一方、後方にあるレベルが破棄されます。移動が完了すると最終的に下図③のような状態になります。このようにプレイヤーの移動に合わせて適宜レベルの読み替えを行い、必要最小限のデータのみを処理するのです。

①座標Aでの状態 ②座標Aから座標Bに移動中の状態 ③座標Bでの状態
streaming streaming streaming
levelstatus

レベルの読み込みがゲームの更新サイクルに対して非同期に行われれば、実際にはシーン全体の一部分しか存在しないにもかかわらず、プレイヤーをあたかもひとつながりの巨大なシーンにいるかのように錯覚させることができます。アイデアとしてはシンプルですが、この手法はとても効果的に動作します。
ゲームエンジンにはこのようなレベルのストリーミングの管理を支援するため機能が組み込まれていることがほとんどです。詳細について知りたい方は、公式ドキュメント(UE4)などをご参照ください。

Enlighten 3.09での課題

Enlightenはグローバルイルミネーションという複雑な光の相互作用を取り扱います。これはシーン中に配置された各オブジェクトが互いに影響して生み出される効果であるため、適切に計算するためにはシーン全体から必要な情報を抽出しなければなりません。Enlighten 3.09まではPrecompute時にシーン全体をロードして影響する可能性がある箇所の絞り込みを行っていました。この実装はシーン規模がそれほど大きくない場合は問題なく処理することができますが、一定以上の広さになってくると莫大な量のメモリが必要になります。これによりメモリスワップが高頻度で発生するようになり、Precomputeにかかる時間が著しく増加してしまいます。

Enlightenは内部的にはシーンをより細かいシステムという単位に分割してラジオシティのデータを管理しています。各システムが必要なデータを生成するとき、前述のようにそのシステムが影響する周囲のシステムを考慮する必要があります。システムが互いに影響するかどうか判定するには、システム間の可視性を検査します。愚直にこれを行うと、すべてのシステムを読み込んでレイトレースを行うような処理が必要になりますが、これはメモリ的にも処理負荷的にもコストが高いことは言うまでもありません。

もし各システムの関係性について何らかの手掛かりがあれば、すべてのシステムについて確認を行う前に予め計算対象から除外することができます。このようなフィルタリングを前処理として行うことで、効率的にシステム間の影響の有無を判定できるようになるはずです。

Enlighten 3.10でのアプローチ

Enlighten 3.10ではレベルのストリーミング情報をフィルタリングの手掛かりとして与えることでこの問題に対応しました。これは特定のレベルに影響する可能性のあるレベルは、そのレベルが読み込まれている時に同じく読み込まれているレベルに限定しても差し支えないという仮定に基づいたものです。なおシステムとレベルの関係性についての詳細説明はここでは割愛させていただきますが、異なるレベルに属するインスタンスが同一システムに含まれることはありませんので、レベルの分割単位をそのままシステムに対して適用できます。

実際に各レベルが同時に読まれることがあるかを判断するためには、各レベルの境界情報とストリーミング距離が必要です。以下の図のようなイメージで判定を行います。

同時にロードされるレベルA、B 同時にロードされないレベルA、B
streamed notstreamed

このようにして影響する可能性のあるレベルの絞り込みを行い、詳細なテストを行う際に読み込む範囲を最小限にすることで必要なメモリ量を大幅に削減することができます。

余談になりますが、ここで計算された各システムの影響候補は中間データとして出力してPrecomputeに渡しています。SDK版を利用し自社エンジンにEnlightenの組み込みを行う場合でも、同様の実装を行うことでUE4版と同じくOut-of-core precomputeを活用することができます。詳細な設定方法に関してはドキュメントのRadiosity dependenciesをご参照ください。

エディタでの設定方法

依存関係に関する設定

ストリーミングの管理にワールドコンポジションを使用している場合、各レベルに設定されたストリーミング距離が自動的に考慮されるようになります。特別な設定を行うことなく、インゲーム時に同時にロードされるレベルのみを対象として依存関係を計算します。

更なる最適化を行いたい場合は、ワールド設定の「Enlighten Bounce Distance」を使用します。このパラメータに有効な値が設定されていれば、レベル間の依存関係をより厳しい条件で判定させることができます。

ワールドコンポジションを使用せず、マニュアルで(コードなどから)ストリーミングの管理を行うケースにおいてもこの設定は有用です。その場合、各レベルが一律でこの距離をストリーミング距離として使用します。

Precomputeコマンドレットに関する設定

Out-of-core precomputeのために実施された修正は上記の依存関係に関するものに加えて、コマンドレットに対する最適化があります。ナイトリービルドなどでEnlightenのPrecomputeを自動化している場合、Precomputeをエディタからではなくコマンドレットから実行しているかと思います。Enlighten 3.10ではそれらに対して実行時に必要最低限のレベルのみを読み込むOut-of-coreモードを追加しました。

この機能は一部既存機能と互換性がないため、デフォルトでは無効となっています。有効化するには、ワールド設定から「Share Lightmaps Across Levels」のチェックを外し、Detailライティングモード使用時にレベル間でのライトマップ共有を無効にする必要があります。(※機能の詳細についてはドキュメントをご参照ください。)

まとめ

Out-of-core precomputeを使用することで、広大なシーンを必要とするゲームを開発する場合でも効率的にEnlightenを設定することができ、Enlightenの提供するリアルタイムグローバルイルミネーションを最大限にご活用いただけます。ぜひ新しいEnlighten 3.10をお試しいただき、そのパワーをご体験ください。

Enlightenのお問い合わせについて

メールでのお問い合わせ

お問い合わせフォームへ

お電話でのお問い合わせ

TEL 03-5488-7481(営業直通)

平日 9:30~17:30

go to top Enlighten