データ指向設計(DOD)とオブジェクト指向プログラミング(OOP)の比較:Unity DOTSとUnreal Engine 5におけるアーキテクチャとパフォーマンスの分析
Unity

データ指向設計(DOD)とオブジェクト指向プログラミング(OOP)の比較:Unity DOTSとUnreal Engine 5におけるアーキテクチャとパフォーマンスの分析

著者GameDev Base
日付2026年10月17日
25分で読める

DOTS と Unreal Mass: スムーズな AAA ゲームのための CPU キャッシュ効率と並列処理のターゲット設定

本レポートでは、ゲーム開発者の視点から、Unity および Unreal Engine 5 ゲームエンジンにおけるデータ指向設計(DOD)と従来のオブジェクト指向プログラミング(OOP)のアプローチを詳細に比較しています。この調査は、特にメモリレイアウトの最適化、CPU キャッシュの利用、マルチスレッドのサポートにおける主要なパフォーマンス結果を分析することを目的としています。本レポートでは、現在のエンジンバージョンにおける具体的なコード例と統合手順を通じて、技術的な詳細に踏み込んでいます。さらに、「Kena: Bridge of Spirits」などのタイトルにインスピレーションを得て、ハイエンド(AAA)のサードパーソン、オープンワールド、モバイルプラットフォーム向けゲームにおけるこれらのアーキテクチャ上の選択の戦略的影響を評価しています。すべての主張は、提供された情報源に基づいて実証されています。

主要なパラダイムの違い:データ保存のロジックとパフォーマンスの結果

データ指向設計(DOD)とオブジェクト指向プログラミング(OOP)の根本的な違いは、データのグループ化を論理単位として行うか、メモリに保存する方法にあります。OOP はデータを機能とともにパッケージ化するオブジェクトに焦点を当てる一方、DOD は同じ種類のデータをまとめて保持することでメモリッチアクセスパターンを最適化することを目指しています。この基本パラダイムの分断は、現代のコンピュータアーキテクチャのパフォーマンスポテンシャルを最大限に引き出す能力において、極めて重要です。

オブジェクト指向プログラミング(OOP)は通常、「データをオブジェクト内に保持する」というロジックに基づいています。キャラクターオブジェクトを想定すると、このオブジェクトは Position(位置)、Health(体力)、Velocity(速度)などの異なるデータ型を含むプロパティを持ちます。各キャラクターオブジェクトは、メモリ内で独自の固有のアドレス領域を占有します。複雑なゲームに何百または何千ものキャラクターが存在する場合、これらのオブジェクトはメモリ内にランダムに分散されます。Update ループですべてのキャラクターを移動させるような処理を実行する場合、CPU は各キャラクターの Position データに個別にアクセスする必要があります。この場合、CharacterA オブジェクトの Position 情報と Health 情報が同じメモリブロックに含まれている可能性は低く、それらは異なるオブジェクトであるため異なるアドレスに存在します。同様に、CharacterB の Position 情報も、おそらく CharacterA のデータからかなり離れています。これにより、CPU がメモリからデータを取得する必要がある際、毎回異なり連続していないメモリブロックにアクセスすることになります。この状況は、現代の CPU の構造と矛盾するパフォーマンスのボトルネックを引き起こします。「Kena: Bridge of Spirits」のようなゲームで発生する突然のカクつきや FPS の低下は、このような OOP ベースのキャッシュ非効率なメモリアクセスパターンに起因するパフォーマンス問題の典型的な兆候です。

一方、データ指向設計(DOD)はこのロジックを逆転させます。DOD はオブジェクトではなく、それらの内容を構成するデータを中心に据え、同じ種類のデータをメモリ内で可能な限り密に、連続して格納することを目指します。このアプローチの最も一般的で形式的な実装が、Entity Component System(ECS)アーキテクチャです。ECS は複雑なエンティティを単純な「エンティティ」として定義し、それらのエンティティの動作とプロパティを独立した「コンポーネント」を介して追加し、これらのコンポーネントを使用する「システム」によって処理します。このアーキテクチャの基盤にあるのは、Structure of Arrays(SoA)またはそれに類するデータ構造です。SoA は、OOP における AoS(Array of Structures)のロジックとは異なり、各データ型に対して個別の配列を作成することを指します。たとえば、すべてのキャラクターの Position 情報は単一の配列(positions[])に、すべてのキャラクターの Health 情報は別の配列(health[])に、すべてのキャラクターの Velocity 情報は3番目の配列(velocity[])に連続して格納されます。この配置により、すべてのキャラクターの位置を同時に更新するタスクにおいて、CPU は大きなデータブロックを1回だけロードするだけで済みます。連続したメモリアクセスパターンにより、CPU は最初のデータがロードされたときに隣接するデータもキャッシュに読み込まれ、これらのデータを繰り返し使用できるため、L1 や L2 などの高速化されたキャッシュを効率的に利用できます。Unity の ECS ドキュメントでは、データがチャンクと呼ばれる固定サイズの連続したメモリブロックに格納され、それが CPU キャッシュラインとどのように高度に適合しているかが強調されています。このシンプルかつ効果的な変更により、特に大規模なデータセットで動作するアルゴリズムのパフォーマンスが劇的に向上します。

特徴オブジェクト指向プログラミング(OOP)データ指向設計(DOD/ECS)データグループ化ロジック「データをオブジェクト内に保存する」(AoS - Struct of Array)「同じデータをまとめて保存する」(SoA - Array of Struct)メモリレイアウトデータはメモリ内にランダムかつ分散して配置されるデータはメモリ内に連続して密に格納されるデータアクセスパターン分散したクロスアクセスが一般的である連続したローカルアクセスが主流であるキャッシュ効率一般的に低い(多数のキャッシュミスの発生)一般的に高い(多数のキャッシュヒットの発生)アーキテクチャの構成継承(inheritance)と抽象化が中心であるコンポーネントで構成される柔軟な構造典型的なアプリケーションUnity GameObjects, Unreal ActorsUnity DOTS/Entities, Unreal Mass

これらの基本パラダイムは、Unity や Unreal Engine 5 などの現代のゲームエンジンにおいて異なる進化の道をたどってきました。Unity は OOP ベースの GameObject アーキテクチャを維持しつつ、DOTS(Data-Oriented Technology Stack)と呼ばれる完全に新しいデータ指向のスタックを導入しました。これにより、開発者はプロジェクトの異なる部分でこれら2つのアプローチを組み合わせて使用する柔軟性が得られます。たとえば、ユーザーインターフェースや特定の特殊なゲームプレイメカニクスは OOP で管理しつつ、物理シミュレーションや多数の AI ユニットの制御は DOD で実行することができます。しかしながら、Unreal Engine 5 の基本アーキテクチャは UObject の継承により深く OOP に依存しています。それでも、Unreal もパフォーマンスが要求される領域に向けて特定のソリューションを開発してきました。最も重要なのが Mass Entity Framework です。Mass は、数百または数千の AI ユニットが同時に動作するシナリオ向けに設計された、データ指向の計算を実行できるフレームワークです。Mass の目的は、Actor/Component アーキテクチャのパフォーマンスの限界を突破することであり、特定のタスク(大規模なユニット管理など)をデータ指向の方法で整理することで並列化の機会を提供します。さらに、Chaos 物理システムもデータ指向のアプローチへと進化しており、シミュレーションの再計算を防ぐためのキャッシュメカニズムを備えています。したがって、両方のエンジンは OOP の柔軟性と DOD のパフォーマンスを統合する方向へ進んでいますが、それぞれのアーキテクチャの背景に起因する異なる戦略を採用しています。

メモリレイアウトと CPU キャッシュ効率の分析

現代のゲームエンジンのパフォーマンスは、CPU が RAM からデータを取得する速度よりも、プロセッサ自体の処理速度の方がはるかに速いという事実によって制限されます。この「フォン・ノイマンのボトルネック」を克服する方法は、CPU の極めて高速でありながら小容量である L1、L2、L3 キャッシュを可能な限り効率的に利用することです。CPU がメモリアドレスにアクセスすると、そのアドレスのデータをメモリから読み取るだけでなく、そのすぐ近くにある数バイト(通常は 64 バイトの「キャッシュライン」)も一緒にキャッシュに読み込みます。次に必要なデータがこのキャッシュライン内にある場合、CPU は高速にアクセスできます。この状態を「キャッシュヒット」と呼びます。そうでない場合は、低速な RAM から新しいデータブロックをロードせざるを得なくなり、これは重大なパフォーマンスのボトルネックとなる「キャッシュミス」と呼ばれます。データ指向設計(DOD)は、特に OOP がもたらす分散したメモリアクセスパターンを回避することで、キャッシュヒット率を高めることを目的としたアーキテクチャ上のソリューションを提供します。

オブジェクト指向プログラミング(OOP)のアプローチは、必然的に分散したメモリレイアウトにつながります。Character オブジェクトには、position、health、rotation などの異なるデータ型を含むメンバーが含まれます。各 Character オブジェクトは、メモリ内で独自のアドレスから始まります。ループ内ですべてのキャラクターの update 関数を呼び出したい場合、CPU はメモリ内の各 Character オブジェクトの先頭に移動する必要があります。これらのオブジェクトのメンバー(データ)は、必ずしも互いに近接しているとは限りません。たとえば、CharacterA の position メンバーと CharacterB の health メンバーは、おそらく同じ 64 バイトのキャッシュライン内には存在しません。これにより、データを順次処理しようとする際、CPU は常に異離れたメモリアドレスにジャンプせざるを得なくなります。毎回新しいアドレスに移行することは、以前のキャッシュラインを無効にすることを意味し、これが高い確率でキャッシュミスを引き起こします。モバイルプラットフォームにおいてこの状況はさらに重要であり、消費電力を抑えながらより多くの処理を行うことが、モバイルデバイスにとっての基本的な利点となります。

データ指向設計(DOD)は、この問題に対する直接的な解決策を提供します。Unity の DOTS アーキテクチャでは、データは「チャンク」と呼ばれる固定サイズの完全に連続したメモリブロックに格納されます。各チャンクには、同じ種類のコンポーネントで構成される「Structure of Arrays」(SoA)配列が含まれています。たとえば、Translation(位置)というコンポーネントに関連するすべてのデータは、単一の連続したメモリブロックに格納されます。同様に、Rotation(回転)データは別のチャンク内、または同じチャンク内の個別の SoA 配列内に連続して配置されます。この配置により、システム(MovementSystem など)は、すべての Translation データを単一の for ループ内で処理できるようになります。CPU はこのループを実行する際、メモリから大きなデータブロックを1回だけロードし、関連するすべてのデータが互いに非常に近接しているため、そのデータを繰り返し利用します。この状況により、CPU キャッシュの効率的な利用が可能になり、キャッシュミス率が劇的に低下します。Unity の ECS アーキテクチャにおけるエンティティが、含まれるすべてのコンポーネントデータを単一のメモリブロックに集約することで、この効率性が最大化されます。さらに重要なことに、Unity の DOTS アーキテクチャにおけるメモリ内のデータのレイアウトは、CPU の独自のメモリ配置(L1 データキャッシュの 64 バイトラインなど)と完璧に一致しています。データフィールドのサイズとアラインメントは、キャッシュラインの要件に合わせて最適化されます。これは、Arm Cortex-X4 のような現代のモバイル CPU において重要な利点となります。なぜなら、これらのアーキテクチャのパフォーマンスは、

メモリ帯域幅とキャッシュ効率が最高レベルであることと直接結びついているからです。

Unreal Engine 5 にも同様の哲学が存在します。Mass Entity Framework は、エンティティとそのコンポーネントを Archetype と呼ばれる複雑なデータ構造に基づいてグループ化することで、メモリ内でのより効率的なストレージを可能にします。Archetype は、特定のコンポーネントのセットを定義します。たとえば、「移動可能で武器を持つ」Archetype を作成できます。その後、これらの種類のコンポーネントを持つすべてのエンティティ(500人の兵士など)は、この Archetype に属するチャンクに自動的に格納されます。これにより、クエリの効率的な実行と、CPU キャッシュの無駄な消費の削減が可能になります。UE 5.7 などの新しいバージョンにおいて、Mass に対する低レベルの最適化が行われていることは、このフレームワークがパフォーマンス重視であることを示す明白な証拠です。さらに、Chaos 物理システムもデータ指向のアプローチに進化しており、シミュレーションの再計算を防ぐためのキャッシュメカニズムが含まれています。Chaos Cache Manager などのツールを使用すると、シミュレーションを1回計算して複数回再生できるようになり、CPU が同じ処理を何度も繰り返すのを防ぐことができます。これにより、動的な破壊や流体シミュレーションなどの CPU 負荷の高い処理において、大幅なパフォーマンス向上がもたらされます。

結論として、メモリレイアウトの最適化と CPU キャッシュの効率性は、現代のゲームエンジンのパフォーマンスを決定する最も重要な要素の1つです。OOP アプローチはデータアクセスパターンを自然に分散させ、CPU キャッシュのポテンシャルを浪費する一方で、DOD はこの問題に対する直接的な解決策を提供します。Unity の DOTS および Unreal Engine 5 の Mass フレームワークは、両方のエンジンにおいて分散したメモリアクセスパターンを回避し、CPU キャッシュを効率的に利用してパフォーマンスを向上させるように設計されています。このアーキテクチャの変更は、「Kena: Bridge of Spirits」のような豊かで活気のある世界を提供するゲームにおいて、求められるスムーズな体験を確保するために極めて重要です。モバイルプラットフォームにおいては、これらの最適化により消費電力を抑えながらより多くの処理を実行できるようになり、省電力化が図られます。

マルチスレッド統合と並列処理能力

現代のプロセッサは複数のプロセッサコアを備えており、これらのコアのそれぞれが独自に動作することができます。マルチスレッドは、この並列処理能力を実際のゲームロジックで活用する機能です。しかし、OOPベースのコード構造では、データ競合を防ぐために複雑な同期メカニズムが必要となり、予期せぬスタッター(カクつき)やCPUコアのアイドル状態を引き起こす可能性があります。データ指向設計(DOD)は、アーキテクチャレベルでこれらの問題に対する解決策を提供し、コードの並列実行を本質的に容易にします。

オブジェクト指向プログラミング(OOP)のアプローチでは、コードは通常、単一のメインスレッド(例えば、Unreal EngineのGameThreadやUnityのMain Thread)上で同期的に行われます。このスレッドは、プレイヤーの入力、AIのロジック、物理演算の更新など、多くのゲームロジックを処理します。他のサブシステム(レンダリング、オーディオ、物理など)は通常別スレッドで動作しますが、これらは多くの場合メインスレッドから独立して動作します。コードの大半が単一のスレッド上で実行されるため、CPUの他のコアは通常アイドル状態で待機します。開発者がOOPベースのプロジェクトに並列性を追加したい場合、データ競合を防ぐためにlock、mutex、semaphoreなどの同期メカニズムを使用する必要があります。これらのメカニズムにより、1つのスレッドがクリティカルセクション(リストに対する書き込み操作など)を終了するまで、他のスレッドが待機することになります。待機時間はCPUコアがアイドル状態になることを意味し、これが予期せぬスタッター(カクつき)や全体的なパフォーマンスの低下につながります。Unreal Engine 5には本来マルチスレッドのサポートが備わっていますが、エンジンが単一のスレッドに縛られることがあり、開発者がこれを最大限に活用することは制限されています。これは、CPUの潜在能力の大半が無駄になっていることを意味します。

データ指向設計(DOD)は、並列処理のために設計されたアーキテクチャパラダイムです。DODは、データを1つの場所から読み込み、1つの場所へ書き込むスレッド間のデータ競合を排除する原則を採用しています。UnityのDOTSアーキテクチャはこの理念の最も明確な例であり、Job SystemとBurst Compilerという2つの主要なテクノロジーを統合しています。Job Systemは、コードを分割し、それらをCPUの異なるコアで並列実行できるようにします。SystemBase内のEntities.ForEachループは、実際にはジョブとしてコンパイルされます。このジョブは、単一のスレッドでのデータの変更を防止することでデータ競合を排除します。各ジョブは、異なるCPUコア上で安全に実行できます。これにより、データ競合を防ぐための複雑な同期コードを必要とせずに並列化を実現できます。Burst Compilerは、C#コードを高度に最適化されたネイティブC++コードに変換するコンパイラ最適化機能です。BurstはLLVMバックエンドを使用してコードをC/C++レベルでコンパイルし、これによりC++から得られるパフォーマンスを達成できるようにします。特にループ、数学的計算、データ変換処理において極めて効率的です。システム内の各SystemBase(MovementSystemなど)は実際にはジョブとして動作し、Burstによって最適化されて異なるCPUコア上で並列実行できます。これにより、単一のスレッドでのデータの変更が防止されてデータ競合が排除され、並列化の安全性が確保されます。

Unreal Engine 5のMass Entity Frameworkも、マルチスレッドの使用を容易にする同様の原則を採用しています。Massは、特定のタスク(何百ものAIの経路探索ロジックの実行など)をデータ指向の方法で整理し、複数のスレッド上で並列実行することでマルチスレッドの使用を容易にします。Massはまた、レンダーグラフなどの他のUnrealのスレッドモデルと統合して動作するように設計されています。これにより、エンジンの異なる部分が異なるスレッドで並列動作することが可能になり、グローバルなパフォーマンスが向上します。Unreal Engine 5.0以降、エンジン自体もマルチスレッドの使用を増やすための改善を行っています。例えば、Vulkan RHIにおける安定性とパフォーマンスのアップデートにより、デスクトップおよびモバイルプラットフォームの両方でより優れたマルチスレッドの活用が可能になりました。

具体的なコード例(Unity DOTS):


public class CharacterController_OOP : MonoBehaviour
{
    public float moveSpeed = 5f;
    void Update()
    {
        
        foreach(var character in allCharacters)
        {
            character.Move(); 
        }
    }
}

using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
public class MovementSystem_DOD : SystemBase
{
    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
       
        Entities.ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
        {
            translation.Value += speed.value * deltaTime * math.rotate(rotation.Value, new float3(0, 0, 1)).normalize();
        }).Schedule();
    }
}

この例では、OOPアプローチがメインスレッド上で同期的に実行される一方、DODアプローチのOnUpdate内のEntities.ForEachループは、Job Systemによって並列処理可能なジョブとしてスケジュールされます。このジョブはBurstによって最適化され、CPUの異なるコア上で同時に実行できます。これにより、単一のスレッドでのデータの変更が防止されてデータ競合が排除され、並列化の安全性が確保されます。

結果として、DODはOOPがもたらす同期の難しさや予期せぬスタッターを排除することで、マルチスレッドの使用を本質的に容易にします。UnityのDOTSおよびUnreal Engine 5のMassフレームワークは、どちらのエンジンでも散発的なメモリッチアクセスパターンを避け、CPUキャッシュを効率的に使用してパフォーマンスを向上させるように設計されています。このアーキテクチャの変更は、特に『Kena: Bridge of Spirits』のような豊かで生き生きとした世界を提供するゲームにおいて、望ましい滑らかな体験を確保するために極めて重要です。モバイルプラットフォーム向けには、これらの最適化により、より少ない電力消費でより多くの処理を行うことが可能になり、省電力が実現します。

Unityエコシステム内のデータ指向技術スタック(DOTS)

Unityは、OOPベースのGameObjectアーキテクチャを維持しつつ、高いパフォーマンスを必要とするアプリケーション向けに、データ指向技術スタック(DOTS)と呼ばれる全く新しい技術スタックを提供します。DOTSは、データ指向設計の原則に基づいてメモリレイアウトを最適化し、CPUキャッシュの効率を向上させ、マルチスレッドのサポートを自然な形で提供します。このセクションでは、DOTSの基本コンポーネント、具体的なコード例、および統合プロセスについて考察します。

DOTSの基礎を形成するのはEntitiesパッケージです。このパッケージは、Entities、Component Data、SystemsなどのECS(Entity Component System)の要素を基本的な形で提供します。ここでの基本理念は、データを機能から切り離し、メモリ内に効率的に格納することです。1. Entiteler: エンティティは、データを一切持たず、一意の識別子を持つ空のコンテナです。Entityはオブジェクトではなく、単なるEntityIdです。これにより、メモリ上で非常に軽量になり、素早く生成および破棄することが可能になります。2. Bileşen Verileri: データを持つstructです。structである必要があり、継承を使用することはできません。例えば、Translation { public float3 Value; }やHealth { public int Value; }のような単純なデータ保持構造体が定義されます。これらのstructはIComponentDataインターフェースを実装します。3. Sistemler: これらのデータを処理するロジックです。SystemBaseクラスから派生したクラスは、特定のデータ型(コンポーネント)を選択するためのクエリを使用し、それらのデータに対して処理を実行します。OnUpdateメソッドはジョブとしてスケジュールされ、通常はEntities.ForEachループを含みます。

具体的なコード例(Unity DOTS):次のコードは、キャラクターの移動をOOPとDOTSでどのように異なる方法で処理しているかを比較しています:


public class PlayerController_OOP : MonoBehaviour
{
    public float moveSpeed = 5f;
    void Update()
    {
      
        float moveInput = Input.GetAxis("Horizontal");
        transform.Translate(Vector3.right * moveInput * moveSpeed * Time.deltaTime);
    }
}

public struct Translation : IComponentData
{
    public float3 Value;
}
public struct Rotation : IComponentData
{
    public quaternion Value;
}
public struct MoveSpeed : IComponentData
{
    public float value;
}
// 2. ゲームロジックを表現するシステム
public class MovementSystem : SystemBase
{
    protected override void OnUpdate()
    {
       
        float deltaTime = Time.DeltaTime;
     
        Entities
            .WithName("MoveEntities")
            .ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
            {
                translation.Value += speed.value * deltaTime * math.normalize(math.mul(rotation.Value, new float3(0, 0, 1)));
            }).Schedule();

        
        Dependency.Complete();
    }
}

この例では、DODアプローチがメモリ内でデータがどのようにグループ化され、処理されるかを示しています。Entities.ForEach内のループは、Burstによって最適化され、異なるCPUコア上で並列実行できる単一のジョブとしてコンパイルされます。これにより、単一のスレッドでのデータの変更が防止されてデータ競合が排除され、並列化の安全性が確保されます。

統合手順(Unity DOTS):DOTSをUnityプロジェクトに統合するには、標準的なUnityプロジェクトの作成から始まり、Package Managerを介して必要なパッケージを追加する必要があります:

  1. パッケージマネージャー: Edit > Project Settings > Packagesメニュー、またはIDE内のWindow > Package Managerメニューに移動します。

  2. 必要なパッケージの追加: 以下の基本的なDOTSパッケージをプロジェクトに追加できます:

    • com.unity.entities: 基本的なECSアーキテクチャを提供するパッケージです。

    • com.unity.jobs: ジョブシステムを実行するために必要なパッケージです。

    • com.unity.burst: C#コードをネイティブC++コードに変換し、最適化するパッケージです。

    • com.unity.mathematics: DOTSで使用されるベクトルや行列演算などの基本数学型を提供します。

    • com.unity.netcode.entities: ネットワーキングをサポートするDOTSアプリケーションに必要です。

  3. データ構造の定義: IComponentDataインターフェースを実装するstructを作成します。これらのstructはデータを保持しますが、関数を含めることはできません。

  4. システムの作成: SystemBaseクラスから派生したクラスを作成します。これらのクラスは、OnUpdate、OnFixedUpdate、OnCreateなどのライフサイクルメソッドをオーバーライドします。

  5. レンダラーの統合: DOTSで作成したエンティティを画面に表示するには、レンダラーが必要です。初期段階では、DOTSデータを既存のGameObjectに反映させるためにHybrid Rendererを使用するのが実用的です。これにより、DOTSのデータ指向アーキテクチャを使用しながら、既存のレンダリングパイプラインを維持することができます。その後、URPやHDRPと統合できるEntities Graphicsパッケージを使用できます。

AAAオープンワールドおよびモバイル最適化のための戦略的影響:『Kena: Bridge of Spirits』のようなゲームでは、豊かで詳細な環境(AAオープンワールド)と、滑らかで反応の良いキャラクターコントロールの両方が求められます。一方、モバイルプラットフォームは、限られたCPU/GPUパワーとバッテリー寿命という追加の課題層をもたらします。

パフォーマンスと滑らかさ:DODは、特にOOPベースのプロジェクトにおける突然のカクつきやFPSの低下を軽減するための最も強力なツールの1つです。『Kena』におけるスタッターの問題は、DODアプローチがもたらす違いを明確に示しています。DODはCPUのフルパワーを使用してより多くのデータ処理能力を提供し、これによりより安定した60 FPSのターゲットを可能にします。

モバイルプラットフォームの最適化:

  • CPUパワー: モバイルCPU(Arm Cortex-X4など)はますます強力になっていますが、エネルギー効率は依然として重要な要素です。DODは、CPUのアイドル時間を最小限に抑えることで、より少ない電力消費でより多くの処理を完了できるようにします。ArmのCortex-X4アーキテクチャにおける33%の帯域幅削減などの改善は、DODで動作するアプリケーションがこれからさらに多くの恩恵を受ける可能性があることを意味します。

  • メモリ管理: モバイルプラットフォームでは、メモリ使用量を厳格に管理する必要があります。DOTSは、メモリ内でより密に配置され割り当てられたデータを扱うことで、全体的なメモリ使用量を削減できます。UnityのAssetBundle圧縮フォーマットやSVT(Virtual Texturing)などのテクノロジーをDODのデータレイアウトと組み合わせることで、モバイルプラットフォーム向けに非常に効率的な構造を構築できます。

  • ProGuard難読化: Android向けのProGuard難読化などのツールを、DODで作成された最適化されたコードと組み合わせて使用することで、配信サイズとパフォーマンスをさらに向上させることができます。

結果として、UnityのDOTSスタックは、OOPのスケーラビリティの限界を克服するために設計された強力なツールセットです。開発者は、プロジェクトのパフォーマンスが重要となる領域(物理、AI、パーティクルシステムなど)でDOTSを使用し、既存のOOPベースの構造を破壊することなくハイブリッドなアプローチを採用することができます。

Unreal Engine 5におけるパフォーマンス重視のアーキテクチャアプローチ:MassとChaos

Unreal Engine 5は、その基本アーキテクチャとしてUObjectの継承に深く根ざしたオブジェクト指向プログラミング(OOP)を中心としています。しかし、AAAタイトルのゲームに求められる高いパフォーマンスと拡張性の要求により、エンジン自体も進化し、データ指向のアプローチに適応せざるを得なくなっています。Unreal Engine 5はこのニーズに応えるため、Mass Entity FrameworkとChaos Physicsという2つの主要なパフォーマンス指向アーキテクチャアプローチを提供しています。これら2つのシステムは、UnrealのOOPベースの構造の枠を超えてデータ指向設計の原則を採用しており、特に大規模なシミュレーションや物理シミュレーションにおいて不可欠なパフォーマンス向上を実現します。

Mass Entity Framework:データ指向ゲームプレイ Massは、Unreal Engine 5におけるデータ指向の計算のために設計されたフレームワークであり、特に数百または数千のゲームユニットが同時に管理されるシナリオ向けに開発されています。Massは、Unrealのゲームプレイを置き換えるのではなく、既存のActor/Componentアーキテクチャの上に構築された、データ指向かつ並列処理に適したレイヤーとして設計されています。その基本哲学は、大量の類似データセットをメモリ内でより効率的にグループ化し、複数のスレッドでそれらを並列処理することによってパフォーマンスを向上させることです。

Massアーキテクチャの主要なコンポーネントは次のとおりです。

  • エンティティ:Massにおけるエンティティは、データを一切持たない、一意の識別子を持つ空のコンテナです。これにより、UnityのEntityのように極めて軽量なものとなっています。

  • コンポーネント:データを保持するデータ構造です。float値、ベクトル、または複雑な構造体などがあります。コンポーネントにより、データをメモリ内でグループ化することが可能になります。

  • システム:特定のコンポーネントを持つエンティティを選択し、それらを処理するロジックです。これらのシステムは、データを処理する際に並列化することができます。

  • アーキタイプ:これはMassアーキテクチャの中で最も重要かつ独自のコンポーネントです。アーキタイプは、特定のコンポーネントのセットを定義します。例えば、「Position」、「Velocity」、「AIController」の各コンポーネントを持つアーキタイプを作成できます。その後、これらのコンポーネントを持つすべてのエンティティ(例:1000体の敵ユニット)が自動的にこのアーキタイプに属するメモリブロックに格納されます。これにより、クエリの実行効率が向上し、CPUキャッシュの無駄な消費を抑えることができます。

具体的なコード例(Unreal Engine 5 - Mass):Massは通常、C++またはBlueprint内の専用ノードを通じて使用されます。以下は、Massシステムの基本構造の概要を示す疑似コードの例です。


USTRUCT(BlueprintType)
struct FPositionComponent
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
    FVector Location;
};
USTRUCT(BlueprintType)
struct FVelocityComponent
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
    FVector Velocity;
};

class FMovementSystem : public FGlobalComponentSystem
{
public:
    virtual void Tick(float DeltaTime) override
    {
      
        Query.ForEach(
            [&](FEntityHandle Entity, FMutableRef<FPositionComponent> PositionComp, FMutableRef<FVelocityComponent> VelocityComp)
            {
               
                PositionComp->Location += VelocityComp->Velocity * DeltaTime;
            });
    }
};
// 3. システムが登録され、エンジンと統合される
IMPLEMENT_MODULE(MyModule, MyModuleName);

この例では、Query.ForEachの呼び出しがMassのデータ指向構造の基礎を形成しています。システムは指定されたコンポーネントを持つすべてのエンティティを選択し、それらのエンティティのデータを1つのループで処理します。このループは、Unrealの内蔵並列処理メカニズムによって異なるスレッドで実行できます。UE 5.7などの新しいバージョンでもMass向けのローレベルな

最適化が続けられており、これは本フレームワークがパフォーマンス重視であることの明白な証拠です。

Chaos物理とキャッシング:

ChaosはUnreal Engine 5におけるデフォルトの物理エンジンであり、OOPアーキテクチャの一部として設計されています。しかし、Chaos自体もデータ指向の原則を取り入れており、特にCPU負荷の高いシミュレーションのパフォーマンスを向上させるように設計されています。Chaosは、破壊可能なジョイントや衝突の反発係数などの機能をサポートしています。

Chaosのパフォーマンス重視の側面における最も重要な特徴は、シミュレーションのキャッシング機能です。複雑な物理シミュレーション(例:大きな建物の崩壊)が毎フレーム再計算される場合、その処理負荷は非常に高くなります。Chaos Cache Managerはこの問題を解決するために設計されています。開発者がシミュレーションを記録すると、エンジンはそのシミュレーションのコピーをメモリまたはディスクに保存します。その後、シミュレーションが再生される際、エンジンは記録されたデータを使用するため再計算を行わず、これにより大幅なCPU時間の節約につながります。これは特に、繰り返しのエフェクトや動的なオブジェクトに対して非常に効果的です。ただし、このシステムが正しく動作するためには綿密な調整が必要です。誤って設定された場合、キャッシュデータが同期せず、オブジェクトが元の位置にスナップしてしまうことがあります。

統合の手順(Unreal Engine 5):

MassやChaosといったシステムをUnrealプロジェクトに統合することは、それらがエンジンのデフォルト構成にすでに含まれていることが多いため比較的容易です。

  1. プラグインの有効化:プロジェクト設定(Settings > Plugins > Gameplay > Mass)からMassプラグインを有効化できます。

  2. BlueprintまたはC++による開発:Massは、Blueprintエディタ内のMass Entityパレットから、または直接C++コードを記述して使用できます。Blueprintサポートは迅速なプロトタイピングに最適です。

  3. システムの作成:MassEntityPlayerControllerなどの用意されたコントローラーを使用するか、FMassExecutionContextを介してC++で独自のシステムを作成することで開始できます。

  4. Chaosの設定:Chaos物理の設定はProject Settings > Chaos Physicsにあります。これらの設定では、衝突の反発係数などの機能を有効にすることができます。Chaosのキャッシングについては、Chaos Solver Settings内のbEnableCacheオプションを有効にする必要があります。

戦略的影響:

Unreal Engine 5のデータ指向アプローチは、特にAAAのオープンワールドやモバイルプラットフォームにおいて戦略的な重要性を持ちます。Kenaのようなスタイルのゲームでは、プレイヤーの前方に常に活気のある広大な世界が存在します。この世界内のNPCやオブジェクトの即時的な挙動がOOPスタイルで管理されている場合、毎フレーム数百もの異なるメモリアドレスにアクセスすることになり、カクつき(スタッタリング)を引き起こします。DODアプローチは、このようなゲームで求められるスムーズな体験を保証するために不可欠です。モバイルプラットフォームにとっては、CPUキャッシュの効率性がさらに重要です。より少ない電力消費でより多くの処理を行うことは、モバイルデバイスにとって基本的なアドバンテージとなります。Unreal Engine 5のNiagaraパーティクルシステムも、SVT(Virtual Texture)などの技術と組み合わせて使用することで、シミュレーションのキャッシングにより重要なパフォーマンスとメモリの改善をもたらすことができます。

結論として、Unreal Engine 5はOOPベースの構造を維持しながら、パフォーマンス重視のニーズを満たすために、強力なデータ指向のレイヤーであるMassとChaosを開発しました。これらのシステムは、大規模かつデータ集約型のシミュレーションに必要なパフォーマンスを開発者に提供すると同時に、エンジンの基本アーキテクチャを変更することなく統合された形で動作します。

戦略的影響と生産性コスト:AAAオープンワールドおよびモバイルプラットフォーム向けの評価

データ指向設計(DOD)とオブジェクト指向プログラミング(OOP)のどちらを選択するかは、単なる技術的な選択にとどまらず、ゲームの成功を左右する戦略的な決定となります。特に、『Kena: Bridge of Spirits』のような豊かで滑らかな広大な世界を持つAAA級ゲームや、リソースが限られたモバイルプラットフォームにおいて、この選択はパフォーマンス、開発速度、そしてゲーム体験に甚大な影響を与えます。DODは、OOPのスケーラビリティの限界を克服するために特別に設計された強力なパラダイムですが、これらのメリットは、学習曲線や統合コストといったコストと相殺して評価される必要があります。

AAAオープンワールドおよびスムーズさの課題に対する戦略的影響:

『Kena: Bridge of Spirits』は、豊かな神話的世界、滑らかなキャラクター操作、そして詳細な環境要素を提供するゲームとして際立っています。Steamコミュニティフォーラムの議論では、ゲームのパフォーマンス上の問題(「スタッター」や「FPSドロップ」)が取り上げられてきました。こうした問題の背後にある根本的な技術的理由は、おそらくOOPベースのアーキテクチャのスケーラビリティの限界にあります。OOPでは、シーン内のすべてのエンティティ(NPC、オブジェクト、パーティクルシステム)が独自のGameObjectと、それに関連付けられたコンポーネントを持っています。これらのGameObjectはメモリ内に分散して保存されるため、毎フレームこれらすべてのエンティティを更新することは、CPUに何百もの異なるメモリアドレスへアクセスするよう命令することになります。これが多数のCPUキャッシュミスを引き起こし、プロセッサは低速なRAMからのデータ取得を余儀なくされ、視覚的なカクつき(突発的な処理落ち)を引き起こします。DODはこの問題に対する直接的な解決策を提供します。UnityのDOTSやUnreal Engine 5のMassなどのフレームワークは、類似のデータ型(例えば、すべてのNPCの位置データ)をメモリ内に連続して格納します。これは、1つのスレッドがこれらすべてのデータを一度にメモリから取得して処理できることを意味し、CPUのキャッシュヒット率と全体的なパフォーマンスを劇的に向上させます。このアーキテクチャは、『Kena』のようなゲームに求められる滑らかな体験を確実にするために極めて重要です。DODはCPUのフルパワーを活用してより多くのデータ処理能力を実現し、より安定した60 FPSの目標を可能にします。

モバイルプラットフォームの最適化に対する戦略的影響:

モバイルプラットフォームは、デスクトップやゲーム機と比較して、CPUパワーの低下、RAMの減少、そして極めて重要な要素であるバッテリー駆動時間など、より限られたリソースしか持っていません。そのため、モバイルゲーム開発者にとって、エネルギー効率とメモリ管理はゲームの成功指標の1つとなります。

  • エネルギー効率: モバイルプロセッサ(例えば、Arm Cortex-X4)はますます強力になっていますが、エネルギー効率依然として重要な要素です。DODは、CPUのアイドル時間を最小限に抑え、より少ない電力消費でより多くの処理を完了できるようにします。ArmのCortex-X4アーキテクチャにおける33%の帯域幅削減などの改良は、DODで動作するアプリケーションがそこからさらに大きな恩恵を受ける可能性があることを意味しています。CPU使用率の低下は、デバイスの発熱を抑え、バッテリーの消耗を遅らせるのにも役立ちます。

  • メモリ管理: モバイルプラットフォームでは、メモリ使用量を厳密に管理する必要があります。DODは、メモリ内でより密集し割り当てられたデータを扱うことで、全体的なメモリ使用量を削減できます。UnityのAssetBundle圧縮フォーマットやSVT(Virtual Texturing)などの技術は、DODのデータ構成と組み合わせることで、モバイルプラットフォーム向けに非常に効率的な構造を作り出すことができます。さらに、UnityのDirectStorageサポートやシェーダーストリーミングなどの新技術も、DODのデータ管理に基づくアーキテクチャの背後にあるビジョンをサポートしています。

    • 生産性と開発時間: モバイルプラットフォーム固有の最適化(例えば、ProGuardの難読化/最小化)やプラットフォーム固有APIの使用は、DODと併せて考慮することで、より効率的なコードベースを構築し、これらの最適化をより効果的なものにします。

生産性コストと開発者エクスペリエンス:

DODが提供するパフォーマンスのメリットは、急峻な学習曲線と初期の生産性低下というコストと相殺して評価されなければなりません。

  • 移行の難しさ: 既存の大規模なOOPベースのプロジェクトを、完全にDODアーキテクチャへ移行することはできません。通常はハイブリッドアプローチが採用されます。一部の重要な領域(物理演算、AI、パーティクルシステム)はDODに移行され、その他の領域(UI、一部の特殊なゲームプレイメカニクス)は既存のOOP構造のまま残されます。UnityのHybrid Rendererはこの種の移行を容易にしますが、完全な統合には課題が伴います。『Kena』における問題は、おそらく既存のOOPベースの構造のスケーラビリティに関連しており、DODのようなアーキテクチャの変更によって解決できることを示唆しています。

    • 経験レベル: DODは、特にOOPの経験を持つ開発者にとって、学習曲線が非常に急である可能性があります。コードを見たときに、「自分のもつオブジェクトがある」というロジックから「このデータセットで何をするか」というロジックへの移行は困難です。これにより、初期の開発速度が低下する可能性があります。

    • ツールエコシステム: OOPベースのUnityとUnrealは、長年にわたって開発され成熟したツールエコシステムを持っています。DOTSやMassなどのDODフレームワークも進化していますが、まだ不十分な点がある可能性があり、ドキュメントの整備もより新しいものとなっています。例えば、DOTSに関連するいくつかのバグ(例えば、バーストアセンブリのロードエラー)や、UnrealにおけるChaos Cache Managerなどのシステムの統合は、依然として開発者にとって課題を生む可能性があります。

比較評価:

基準オブジェクト指向プログラミング(OOP)データ指向設計(DOD)学習曲線低く、一般的で普及しているパラダイム高い、新しい哲学を必要とする生産性(初期)高く、素早いプロトタイプに適している低く、最初は遅くなる可能性があるパフォーマンス(スケーラビリティ)制限があり、大規模データセットに対して遅くなる高い、数百万のデータに対して良好にスケールするCPUキャッシュ効率低く(分散アクセス)高く(連続アクセス)並列処理の容易さ中程度(同期が必要)高い(本質的に並列)モバイルプラットフォームへの適合性妥当だが、エネルギー効率は低い高い、CPUをより効率的に活用する統合(既存プロジェクト)容易、既存プロジェクトと直接互換性がある困難、ハイブリッドアプローチを必要とする

結論と戦略的推奨:

OOPとDODのどちらを選択するかは、ゲームの規模、ターゲットプラットフォーム、チームの専門分野などの要因によって異なります。小規模から中規模のプロジェクト、または迅速なプロトタイピングにおいては、OOPが開発速度と柔軟性の面で有利になる可能性があります。しかし、『Kena: Bridge of Spirits』のような滑らかでリッチで広大な世界を含むAAA級のゲームにとって、DODはパフォーマンスとスケーラビリティの観点から不可欠な選択肢になりつつあります。一方、モバイルプラットフォーム向けには、DODはエネルギー効率の向上やメモリ使用量の削減といった付加価値をもたらし、より一層魅力的なものとなります。開発者はプロジェクトの要件を慎重に分析し、OOPの柔軟性とDODのパフォーマンスを組み合わせたハイブリッド戦略の採用を検討すべきです。これにより、プロジェクトの異なる部分に適切なアーキテクチャを適用することが可能になります。

*情報:画像は、Google Geminiによって生成されました。

UnityUE5UnityDOTSMultithreadingChaosPhysics
ディープリサーチツール
Qwen (Alibaba Cloud)
Qwen (Alibaba Cloud)
翻訳ツール
Google Gemini
Google Gemini

共有
データ指向設計(DOD)とオブジェクト指向プログラミング(OOP)の比較:Unity DOTSとUnreal Engine 5におけるアーキテクチャとパフォーマンスの分析 | GameDev Base