DrakkenRidge: Building an open-world adventure for mobile VR
Simeon Acker and Cyril Guichard - Garage Collective
GUEST BLOG
Made with Unity、ドラッケンリッジGarage Collectiveが開発したオープンワールドアクションRPGで、モバイルVR向けに設計・最適化されています。今回のゲストブログでは、Unityのエンティティコンポーネントシステムをレンダリングの基盤として使用しながら、様々な設計およびパフォーマンス技術をどのように活用しているかについて、チームが解説します。

DrakkenRidg VRのご紹介
私たちはGarage Collectiveです。VR向けに開発されたオープンワールドアクションRPG『 DrakkenRidge』の開発チームです。このゲームでは、地平線に見えるあらゆる場所を訪れることができます。強力な魔術師ハンターとなって、美しく手作りされた6つの島々を探る。それぞれの島は完全に一意ので、独自のキャラクター、クエスト、ダンジョン、そして秘密が隠されている。
この旅は、暖かく快適なビーチから息を呑むような雪山の峰々へ、緑豊かな神秘的な森から地球の奥深くにある危険な峡谷へとあなたを誘います。新しいアイテムを作り、精巧にデザインされた数十種類のクリーチャーや敵と戦い、あらゆる遭遇を一意の体験に変えることができる新しい魔法の系統を解放しよう。
エンティティコンポーネントシステムがなければ、この規模のゲームを2人チームで開発することは恐らく不可能だったでしょう。この記事では、これらのツールを使って広大なアドベンチャーゲームを制作した方法について解説します。
よりスムーズなゲーム開発のためのミキシング技術
ECSを使ってゲームをビルドことにはいくつかの大きな利点がありますが、小規模な独立系スタジオである私たちは、モバイルVR向けにDrakkenRidgeをどのように設計・開発するかを決定する際に、他の要素も考慮する必要がありました。
ECSを使用する際の主な課題は2つあります。
- 急な学習カーブ:ECSを用いた開発には、従来のオブジェクト指向ロジックからの完全なパラダイムシフトが必要となる。
- エンティティシステムと従来のゲームオブジェクトシステムが分離していると、両者の相互作用が難しくなる可能性がある。
そこで、私たちにとっての疑問は次のようになった。
どのオブジェクトとインタラクションがECSの機能を活用すべきで、どのオブジェクトは従来通りのGameObjectsやMonoBehaviourのままにしておくべきでしょうか?
ドラッケンリッジのEntities
DrakkenRidgeは広大なオープンワールド環境で構成されており、特定のスペースに数万ものオブジェクトが存在し、プレイヤーは常に数千ものオブジェクトを目にすることができる可能性がある。
これらを従来のGameObjectsとしてレンダリングするには、大きなメモリオーバーヘッドが必要となり、エンジンはシーン階層全体を評価し、各オブジェクトの Transform コンポーネントを計算する必要があります。数千ものオブジェクトをレンダリングする場合、特にモバイルデバイスでは、GPUの負荷が著しく低下します。
では、これらのオブジェクトをEntitiesとしてレンダリングするたらどうなるでしょうか?

Entitiesとして、 GameObjectsに関連するレンダリングとメモリのオーバーヘッドの多くを回避し、代わりにEntities Graphicsを使用してメモリ チャンクにまとめて格納されます。システム。
さらに、 DrakkenRidgeのアートパイプラインではテクスチャアトラスという技術を多用しており、広大な環境でも使用するマテリアルの総量を削減しています(テクスチャアトラスに関するブログ記事はこちらをご覧ください)。
Entities Graphicsは、共通のメッシュとマテリアルを共有すべてのオブジェクトをグループ化して処理することができ、その後、エンジンは密に詰め込まれた描画呼び出しを作成し、多数のオブジェクトを一度にレンダリングするできます。
その結果、数百ものバッチ処理とSetPass呼び出しを削減できる。

わずか8回のSetPass呼び出しで数千のオブジェクトをレンダリング
カスタムエンティティシステム
DrakkenRidgeは、数千ものオブジェクトを一度にレンダリングするためにECSを利用しています。しかし、これによって大幅なパフォーマンス向上が実現したとしても、モバイルVRプラットフォームでの体験をさらに向上させるためにできることはまだたくさんあります。
遠隔オーサリングシステム
DrakkenRidge Entities向けに最初に開発した特徴は、距離作成システムです。オブジェクトをプレイヤーに対して非表示にするか表示するかを決定するために、さまざまな変数をアカウントに入れます。
オープンワールドではプレイヤーの視界が非常に広いため、何千もの遠くの物体が一度に視界に入る可能性がある。このシステムは、これらのうちどれを目立つように表示し、どれを背景にフェードかを優先的に判断します。距離のフォグなどの環境効果は、遠くの物体が視界からフェード際の遷移を表現するために用いられる。

ランタイムエンティティカリング用のカスタム値を持つ距離オーサリングコンポーネント
各エンティティに対して、さまざまなパラメータに基づいて、エディタ内で固有のカリング値が生成されます。このデータは、エンティティ作成時にシステムに渡されます。これは、事前に計算されたデータを使用して、Entitiesをレンダリングまたはカリングするタイミングについてランタイム時に決定を下します。
カスタムエンティティグループ
DrakkenRidgeの距離オーサリングシステムを使用すると、エンティティを共有の意思決定処理を持つグループに割り当てることができ、例えば、都市内の各エンティティが個別に決定するのではなく、ゲーム内のさまざまな要因に基づいて都市の一部を迅速にレンダリングまたは削除することが可能になります。

意思決定処理を共有するグループ化されたEntities
エンティティLOD
DrakkenRidgeの距離オーサリングシステムの3つ目の特徴は、エンティティを、レンダリングするがさらに低い別のエンティティにその場で置き換えることができる点です。この手法は元々、より高価なシェーダーやマテリアルに関する問題を解決するために考案されたものです。
DrakkenRidgeの環境モデルは既に高度に最適化されているものの、一部のシェーダーは目立った処理負荷を追加する。このエンティティLOD (詳細度レベル)システムでは、必要な場合にのみ「よりコストの高いシェーダーを使用したエンティティのバージョン」をレンダリングすることができます。
/// If using a simplified LOD object, see if we are in its range
if (inDistanceReturn.useLOD)
{
if (inDistanceReturn.isInDistanceLOD)
{
ecbParallel.SetEnabled(unfilteredChunkIndex, inDistanceReturn.lodEntity, true);
if (ChildLookup.TryGetBuffer(inDistanceReturn.lodEntity, out lodChildBufferData))
{
var newParent = inDistanceReturn.lodEntity;
SetEnableChildren(
entityCanBeReEnabledComponentLookup: entityCanBeReEnabledComponentLookup,
unfilteredChunkIndex: unfilteredChunkIndex,
parentEntity: newParent,
enabled: true,
childBufferData: lodChildBufferData,
ChildLookup: ChildLookup,
ecbParallel: ecbParallel);
}条件が満たされた場合は、エンティティに対して簡略化されたLODを使用します。
CPU最適化
DrakkenRidgeの距離計算処理は、CPUパフォーマンスを最大化するために、バーストコンパイルされたジョブを通して実行されます。
Unityジョブは、背景で実行される非同期タスクとしてスケジュールできる関数であり、 Burst Compiler はCPU負荷の高いタスクを高度に最適化されたネイティブマシンコードに変換することで、処理速度を向上させます。
[BurstCompile]
public partial struct ProcessBufferJob : IJobChunk
{
internal EntityCommandBuffer.ParallelWriter ecbParallel;
public EntityTypeHandle entityTypeHandle;
[ReadOnly] public BufferTypeHandle<Child> childTypeHandle;
[ReadOnly] public ComponentTypeHandle<DistanceCompData> distanceCompDataTypeHandle;
// A BufferLookup for random access to Child buffers.
[ReadOnly] public BufferLookup<Child> childLookup;
[ReadOnly] public ComponentLookup<Disabled> disabledComponentLookup;
public PlayerDesignatorCompData targetDesignator;
public HelperStructToUpdateEnabledEntities addToBufferStruct;
public Entity playerEnt;
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
var entities = chunk.GetNativeArray(entityTypeHandle);
var childAccessor = chunk.GetBufferAccessor(ref childTypeHandle);
var distanceCompData = chunk.GetNativeArray(ref distanceCompDataTypeHandle);
bool hasChildBuffer = chunk.Has(ref childTypeHandle);
DynamicBuffer<Child> lodChildBufferData;
for (int i = 0; i < chunk.Count; i++)
{
Entity currentEntity = entities[i];ヒント:DynamicBuffer の最適化の1 つは、イテレーションの前に NativeArray にキャストすることです。「var lodChildNativeArray = lodChildBufferData.AsNativeArray();」
DrakkenRidgにおけるGameObjectsと物理演算
DrakkenRidgeでは、ワールドの90%がECSを使用してレンダリングされており、ECSは背景で独自のタスクを実行して、視覚的に認識できる環境を美しく最適化されたステートに保っています。
しかし、プログラマー1名とアーティスト1名という小規模な開発チームだったため、近接VRインタラクションの多くを従来のGameObjectsとMonoBehaviorを使用してビルドことに決定しました。これにより、迅速なテストと頻繁な設計サイクルが行われる環境において、イテレーション時間を短縮することが可能になった。
物理相互作用と戦闘
DrakkenRidgeにおけるVRインタラクションは、主に物理演算シミュレーションによって実現されている。これには、物体をつかんで操作する動作から、プレイヤー登攀やパルクール、魔法の発動や近接戦闘まで、あらゆる動作が含まれます。
プレイヤーは物理法則に基づいたクライミングチャレンジに対話するできます。
オープンワールドで物理演算シミュレーションを実行する
DrakkenRidgeの戦闘は、一意のモーションと関節ごとの物理演算挙動を組み合わせたシステムによって実現されています。各AIは、状況に応じて、自身の死が反応的で満足のいくものとなるように、どのように演出するかを決定する。
関節ごとの物理演算とスクリプトによるアニメーションを組み合わせることで、一意の反応をビルド。
DrakkenRidgeには、プレイヤーが一度に複数の敵にダメージを与えることができるアイテムや呪文が多数存在し、その結果、多くのキャラクターリグ上で同時に物理演算シミュレーションが実行されることがよくあります。
爆発物理演算をAIグループに適用する
物理最適化
リアルタイムの物理演算シミュレーションは、特にモバイルプラットフォームではコストがかかる場合がある。これを軽減ヘルプために、ゲームワールドの各物理演算オブジェクトはプレイヤーの位置と、プレイヤーがシミュレーションと対話するできる位置にいるかどうかを追跡します。
例えば、プレイヤーは物理法則に基づいて構築された長い鎖を登ることができ、それらの鎖は互いに、そして周囲のワールドと対話する。これらの物理演算ライダー、ジョイント、およびリジッドボディは、プレイヤーを直接操作しているか、またはチェーンを視界に入れているかに基づいて、動的に有効/無効にされます。
原則として、遠距離にあるオブジェクトもレンダリングするが、物理演算相互作用は近距離にあるオブジェクトとの間でのみ許可します。VRゲームでは、アクションが間近で起こるため、これはプレイヤーの期待に合致する。
さらなる最適化
モバイルVR向けレンダリングの最適化方法を決定するにあたり、各環境がどのように構築されているかを考慮し、ニーズに最適なソリューションを選択しました。
ECSに加えて、LODやインポスターなど、さまざまな手法を検討しました。
ゲームオブジェクトのLOD
LOD を使用したGameObjectsのレンダリングは、特定のオブジェクトの複数のバージョンをプレイヤーからの異なる距離でレンダリングすることから成ります。例えば、プレイヤーがオブジェクトから遠く離れている場合、非常に詳細な家のモデルは、非常に簡略化されたローポリゴンバージョンに置き換えられ、レンダリング時間を節約します。
DrakkenRidgeでは、すべてのオブジェクトが既に高度に最適化されたローポリゴンのレトロアートスタイルでモデリングされており、ワールドの大部分はECSによって処理されているため、従来の3D LODを使用しても実際には何のメリットもありません。
しかし、距離執筆私たちが作成したシステムは、必要に応じて遠方のEntitiesのLOD(レベル・オブ・ディテール)のレンダリングを処理するように構築されています。
偽者
インポスターシステムは、プレイヤーが3DGameObjectsから一定の距離にいる場合、それらを2Dのビルボードに変換します。これは、森林のような密集した遠景の背景オブジェクトに対して最も効果的です。DrakkenRidge は場合によっては詐欺師を利用します。

適切に実装された偽物は、 3Dの実物と見分けがつかない。
DrakkenRidgeでは、さまざまな最適化手法をテストし、どれを採用するかを慎重に選択しました。Unity ECSは圧倒的に優れたパフォーマンス向上を実現し、従来のゲームオブジェクトパイプラインを使用する場合に比べてはるかに低いコストで、ゲームワールド全体をレンダリングすることができました。
最後に
DrakkenRidgeにおいては、デザインと最適化技術の組み合わせが完璧なレシピとなり、一意のVRアドベンチャーをビルドことができました。オープンワールドはUnityのECSによって動作し、近接インタラクションは使い慣れたゲームオブジェクトと物理演算ワークフローで設計されているため、チームは迅速に設計、テスト、反復することができます。
モバイルVR向けのオープンワールドRPGは、決してリーチないものではありません。今後、より多くの開発者がこの冒険に挑戦してくれることを外観フォワード!

DrakkenRidge VRが発売されました。SteamキュレーターページでMade with Unityゲームをもっと探したり、 UnityブログやリソースハブでUnity開発者によるストーリーをチェックしたりしてみてください。