🎮

Unity 6がいよいよ本気でゲーム開発者へオブジェクト指向を捨て去りDOTSに移行することを推奨〜関数型プログラミングとの関係性は?

2024/06/03に公開

Introducing our new e-book: Unity’s Data-Oriented Technology Stack (DOTS) for advanced developers / 新しい電子書籍のご紹介: 上級開発者向けの Unity のデータ指向テクノロジー スタック (DOTS)


Unity のデータ指向テクノロジースタック (DOTS) を使用すると、 ターゲットハードウェアを最大限に活用できるパフォーマンス強化ツールスイートが提供され、大規模で複雑なゲームを作成できます。

50 ページを超える電子書籍「上級 Unity 開発者向けのデータ指向テクノロジー スタック入門」が、無料でダウンロードできるようになりました。データ指向プログラミングをより深く理解し、次のプロジェクトに DOTS が適しているかどうかを評価するための入門書としてご利用ください。新しい DOTS ベースのプロジェクトを開始する場合でも、Monobehavior ベースのゲームのパフォーマンスが重要な部分に DOTS を実装する場合でも、このガイドは必要なすべての基礎を体系的かつ明確にカバーしています。

Unity 6 がプレビュー中で、DOTS 1.0 が製品版に対応している今こそ、DOTS がもたらすチャンスを探る絶好の機会です。Unity のシニア ソフトウェア エンジニアである Brian Will が執筆したこの電子書籍は、更新された Unity Learn サンプル、最近の DOTS ブートキャンプ、GitHub サンプルとともに、DOTSの使い方を学びたい開発者が利用できるリソースのコレクションに加わります。


E-BOOK

Introduction to the Data-Oriented Technology Stack for advanced Unity developers

image


この新しい電子書籍は、DOTS パッケージとテクノロジーの一部またはすべてを実装することが、既存または今後の Unity プロジェクトにとって適切な決定であるかどうかについて、十分な情報に基づいた判断を下すのに役立ちます。各 DOTS パッケージと、主に Unity Entity Component System (ECS)を基盤とする概念について説明します。取り上げる機能は次のとおりです。

  • C# ジョブ システム
  • バーストコンパイラ
  • コレクション
  • 数学
  • エンティティ
  • エンティティ グラフィックス
  • ユニティ物理学
  • エンティティのネットコード

また、基本的な DOTS 機能と高度な DOTS 機能の両方を紹介する多くのサンプルを含む ECS GitHub リポジトリの概要も紹介します。

最後に、付録では、メモリ割り当てとガベージコレクション、メモリと CPU キャッシュ、マルチスレッドプログラミング、 オブジェクト指向プログラミングの制限、データ指向プログラミング など、Unity ECS に関連する概念について詳しく説明します。

E-BOOK内容ピックアップ

通常のUnityプロジェクトにおけるコードは、キャッシュに優しくない傾向があります。

従来のC#およびUnityのAPIはオブジェクト指向のコードスタイルを奨励 しており、このスタイルは多数の小さなメソッドや複雑な呼び出しチェーンを伴います。データ指向のアプローチとは異なり、ハードウェアに優しくありません。

— すべてのMonoBehaviourのイベント関数は個別に呼び出され、その呼び出しは必ずしもMonoBehaviourのタイプごとにグループ化されていません。例えば、1000のモンスターMonoBehaviourがある場合、各モンスターは個別に更新され、他のモンスターと一緒に更新されるわけではありません。

— 従来のC#および多くのUnity APIのオブジェクト指向スタイルは、一般的に抽象化の多いソリューションにつながります。その結果、コードには解消が難しい非効率が随所に見られる傾向があります。


(DOTS)パッケージを深く掘り下げていくうちに、開発者の視点から非常に興味深いものであることがわかりました……それは完全に新しいパラダイムでした。オブジェクト指向ではなく、データ指向のものでした……多くの話し合いと議論を経て、私たちは前進することを決め、DOTSとECSについての知識に投資しました。


彼らはオブジェクト指向プログラミングの欠点を避けるために、UnityのECSフレームワークを活用しました。「MMOはECSにとって素晴らしい適用例です」とCTOのローレン・フレイジャーは述べています。「Zenithは数千のエンティティが同時に共存することを必要とし、ECSは私たちにスケールでの実行を可能にします。


DOTSのデータ指向要素は、MonoBehaviourプロジェクトから知っているオブジェクト指向プログラミングアプローチよりもハードウェアに優れています。DOTSに関連する、通常のMonoBehaviourベースのC#プログラミングではあまり関連しないいくつかの重要な概念を理解することが役立つでしょう。


オブジェクト指向プログラミングのコスト

オブジェクト指向プログラミングのパフォーマンスコスト

オブジェクト指向プログラミング(OOP)にはいくつかのパフォーマンスコストが伴います。

データレイアウトの分散: OOPコードは多くの小さなオブジェクトに分割されることが多く、データはメモリ全体に分散してしまうことがよくあります(前のセクションで議論されたキャッシュの非効率性につながります)。

過度な抽象化: オブジェクト指向設計はしばしば多くの委譲層を奨励し、上位層が実際の作業を下位層に委ねるため、多くのオブジェクトやメソッドが実際にはほとんど作業を行いません。

複雑な呼び出しチェーン: 多くの抽象化層と小さな関数の好みのため、呼び出しチェーンが非常に複雑になります。

仮想呼び出し: 仮想ディスパッチテーブルは通常の関数呼び出しよりもオーバーヘッドを伴うだけでなく、仮想呼び出しは通常インライン化できません(一部のJITコンパイラは実行時にこれを行う場合がありますが)。

悪いメモリアロケーションパターン: OOPが奨励する複雑なコードパスはオブジェクトのライフタイムを考慮するのを難しくし、OOPコードは頻繁で小さなアロケーションやガベージコレクションに頼る傾向があり、より効率的な代替手段を取ることが難しくなります。

一度に一つずつの処理: オブジェクトを直接操作するコードがオブジェクト自体の一部であるため、OOPにはオブジェクトを一つずつ処理する傾向があります。

オブジェクト指向プログラミング(OOP)の構造的コスト

最適なパフォーマンスを犠牲にしてでも、プログラムの記述や保守を容易にすることを優先するとしても、OOPにはその領域でも短所が存在します。以下にいくつか挙げます。

  1. データとコードの絡み合い データとコードを絡めることで、両方がより乱雑で複雑になります。OOPはデータを重視すると言われていますが、実際にはデータとコードが絡み合っています。オブジェクトの機能はそのデータに直接関連しており、オブジェクトが何をできるかはその定義に不可欠で、データから切り離すことができません。この絡み合いはしばしば次のような疑問を招く設計選択につながります:

    • データのみを持つべきオブジェクトがコードを持っている。
    • コードのみを持つべきオブジェクトがデータを持っている。
    • コードの目的でデータをグループ化するオブジェクト。
    • データの目的でコードをグループ化するオブジェクト。
    • データのためにオブジェクトに分割されたコード。
    • コードのためにオブジェクトに分割されたデータ。
  2. 集中した複雑性を分散した複雑性に置き換えることで、全体の複雑性が増加する OOPの設計ルールによれば、責任が多すぎるオブジェクトは小さなオブジェクトに分割されるべきですが、大きなものを小さく分割すると、全体の複雑性が減るのではなく、散らばってしまうことがあります。多くの小さな部分があるコードベースでは、どのデータやコードがどの機能に関連するかを理解するのが難しくなります。

  3. オブジェクトはどのコードがどのデータにアクセスしているかを追跡するのを難しくする プログラムを理解するには、そのデータとそのデータがどのように変換されるかを理解することが不可欠です。オブジェクト指向プログラムでは、オブジェクト同士の関連が増えるほど、これらの判断が難しくなります。オブジェクトのカプセル化はデータへの直接アクセスを非公開にするかもしれませんが、間接的に接続されたオブジェクトは公のメソッド呼び出しの経路を通じて間接的にアクセスできる場合があります。例えば、値が誤って設定される理由をデバッグする際には、関連するすべてのコード経路を特定するのに多くの労力が必要になるかもしれません。一方、厳密な手続き型プログラムでは、データに影響を与える可能性のあるすべてのコード経路を特定するのは通常、考慮すべき可能性が少なくなります(グローバル変数を乱用しない限り)。

このように、オブジェクト指向プログラミングには、データとコードの絡み合いや複雑性の分散、データアクセスの追跡の難しさなど、いくつかの構造的なコストが存在します。

DOTS (Data-Oriented Technology Stack) の説明【ChatGPT-4o】

Unity DOTS (Data-Oriented Technology Stack) は、マルチコアプロセッサを最大限に活用することで高性能なゲームを作成するのに役立つ技術群です。以下にその主なコンポーネントの概要を示します。

1. ECS (Entity Component System)

ECSは、データと動作を分離するデザインパターンで、コードの再利用性とゲームのパフォーマンスを向上させます。エンティティとそのコンポーネントをキャッシュ効率と並列処理に最適化された方法で管理します。

  • エンティティ: ゲーム内のオブジェクトに対する一意の識別子。
  • コンポーネント: 動作を持たない純粋なデータのコンテナ。コンポーネントはエンティティのデータを保持します。
  • システム: 特定のコンポーネントを持つエンティティに対して動作を行うプロセス。システムは並列化可能なロジックを含みます。

2. C#ジョブシステム

C#ジョブシステムは、安全なマルチスレッドコードの記述を可能にします。全てのCPUコアを活用し、並列実行可能なジョブ(作業単位)をスケジュールします。

  • ジョブ: 並列実行可能な作業単位。
  • ジョブスケジューラ: 複数のコアにわたるジョブの実行を管理します。
  • バーストコンパイラ: C#ジョブを高度に最適化された機械語に変換するコンパイラ。

3. バーストコンパイラ

バーストコンパイラは、C#ジョブのための最適化コンパイラで、高度に最適化されたネイティブコードを生成します。ジョブシステムと連携して、計算集約型のタスクに対して大幅な速度向上を提供します。

Unity DOTSの利点

  • パフォーマンス: データレイアウトと並列実行の最適化によるパフォーマンスの大幅な向上。
  • スケーラビリティ: 複雑なシミュレーションや大規模なゲームに適したマルチコアプロセッサでのスケーラビリティの向上。
  • メンテナビリティ: データとロジックの明確な分離による、クリーンで保守しやすいコード。

ユースケース

  • 複雑なシミュレーション: 多くのエンティティやコンポーネントを扱うゲーム(大規模な群衆や複雑な環境の相互作用)。
  • リアルタイムストラテジーゲーム: 多数のユニットとその相互作用の効率的な管理。
  • 物理シミュレーションとAI: 物理シミュレーションやAI行動の高性能計算。

始め方

  1. DOTSパッケージのインストール: Unity Package Managerから必要なDOTSパッケージ(EntitiesBurstJobsなど)をインストールします。
  2. エンティティとコンポーネントの作成: エンティティとそれに対応するコンポーネントを定義します。
  3. システムの実装: エンティティとコンポーネントを処理するシステムを作成します。
  4. バーストによる最適化: バーストコンパイラを使用してジョブの実行を最適化します。

まとめ

Unity DOTSは、データ指向のアプローチを強調し、パフォーマンスとスケーラビリティを重視したゲーム開発の新しい方向性を示しています。これにより、モダンなゲームの作成に強力なツールとなります。

DOTSと関数型プログラミングの関係性は?【ChatGPT-4o】

Unity DOTS (Data-Oriented Technology Stack) と関数型プログラミングは、多くの概念的な類似点があり、その基礎となる原則や利点において密接に関連しています。以下に、DOTSと関数型プログラミングの共通点を論じます。

1. 不変性

関数型プログラミング: 不変性は関数型プログラミングの核心原則の一つです。データ構造は不変であり、一度作成されると変更されません。変更が必要な場合は、新しいデータ構造が作成されます。

DOTS: DOTSは不変性を厳密に強制するわけではありませんが、状態の変更と副作用を最小限に抑えることを推奨しています。ECSのコンポーネントは、システムの実行中は不変として扱われることが多く、変更はバッチ処理され、制御された方法で適用されます。これにより予測可能で信頼性の高いコードが実現します。

2. 純粋関数

関数型プログラミング: 純粋関数は、同じ入力に対して常に同じ出力を生成し、副作用を持たない関数です。これにより、コードの理解とテストが容易になります。

DOTS: DOTSのシステムは純粋関数として設計することができます。これらのシステムはデータ(コンポーネント)に対して動作し、決定論的な出力を生成し、スコープ外での副作用を引き起こしません。この設計により、テスト性と信頼性が向上します。

3. 第一級関数と高階関数

関数型プログラミング: 関数は第一級市民であり、引数として渡されたり、他の関数から返されたり、変数に代入されたりします。高階関数は他の関数をパラメータとして受け取ったり、結果として返すことができます。

DOTS: DOTSは主にデータ指向設計に焦点を当てていますが、C#のジョブシステムとバーストコンパイラは高階プログラミングを可能にします。ジョブやシステムをパラメータとして渡すことで、より抽象的で再利用可能なコードを作成できます。

4. 並行性と並列性

関数型プログラミング: 関数型プログラミングは並行実行や並列実行と自然に調和します。純粋関数は状態を共有しないため、ロックや同期を必要としません。

DOTS: DOTSは高性能な並列処理を目指して設計されています。C#のジョブシステムとバーストコンパイラはジョブを並列実行することを可能にし、明示的な同期を必要とせずに、不変性と副作用のない設計を活用しています。

5. 宣言型スタイル

関数型プログラミング: 関数型プログラミングは、達成したいことを記述する宣言型アプローチを強調します。

DOTS: DOTSでは、データ(コンポーネント)と操作(システム)を記述し、意図する結果に焦点を当てます。この高レベルの記述により、Unityのフレームワークが効率的な実行とデータ管理を処理することができます。

6. コンポーザブルシステム

関数型プログラミング: 関数やデータ変換は、単純なものから複雑な操作を構築するために組み合わせられます。

DOTS: DOTSのシステムは、コンポーザブルに設計されています。小さく単一目的のシステムを作成し、それらを組み合わせることで複雑な動作を実現できます。このコンポーザビリティは、関数型プログラミングにおける関数合成に類似しています。

結論

Unity DOTSと関数型プログラミングは、不変性、純粋関数、並行性、コンポーザビリティなど多くの原則を共有しています。これらの共通点により、DOTSは関数型プログラミングの概念に親しんだ開発者にとって自然な選択となり、より堅牢でメンテナブルで高性能なゲームコードの作成に役立ちます。

他の紹介記事

New Unity’s DOTS System and What It Means for Game Development

データ指向プログラミングへの切り替え

Unity DOTS システムの変革の本質はその名前そのものに埋め込まれており、ゲーム開発を支配してきた従来のオブジェクト指向フレームワークとは対照的に、データ指向テクノロジーへの戦略的転換を示しています。これらの対照的なパラダイムを詳細に調べると、それぞれのアプローチの核となる違いと利点が明らかになります。

オブジェクト指向プログラミング (OOP) は、独自のデータと動作をカプセル化するオブジェクトに重点を置き、構造化された直感的なコーディング環境を提供することで、ゲーム開発の基盤を構築します。開発者の間で普及しているこの方法は、オブジェクト間の関係が論理的に定義された、よりクリーンで整理されたコードベースをサポートします。

しかし、広く採用され、ソフトウェア開発に明確さをもたらすにもかかわらず、OOP は、特に並列コンピューティングの領域で課題に直面しています。オブジェクト指向モデルは個別のオブジェクトを重視しているため、複数のプロセッサ コア間でタスクを効率的に実行することが複雑になる可能性があります。この制限は、シームレスなパフォーマンスが重要なゲームなどのリソース集約型アプリケーションでは特に、パフォーマンスのボトルネックにつながる可能性があります。

逆に、Unity DOTS フレームワークの基盤であるデータ指向プログラミング (DOP) は、オブジェクトからオブジェクトに含まれるデータに焦点を移します。DOP は、データを同種のグループに整理することで、関連するデータ ポイントの同時処理を容易にし、計算効率を高め、さまざまなオブジェクトに分散しているデータへのアクセスや変更に伴うオーバーヘッドを削減します。

Unity DOTS に代表される OOP モデルから DOP モデルへの移行により、マルチコア プロセッサの潜在能力が最大限に引き出され、データ アクセスと操作が最適化されて実行時間が短縮されます。この移行により、ハードウェアをより効率的に使用してゲームのパフォーマンスが向上するだけでなく、キャッシュ利用の有効性も大幅に向上します。このようなアプローチにより、ゲーム開発者はパフォーマンスを犠牲にすることなく、より複雑で動的なエクスペリエンスを作成できます。

Unity Technologies が Unity DOTS システムを採用したことは、最新のハードウェア機能に合わせた高度なツールを開発者に提供するという同社の取り組みを強調するものです。Unity DOTS を開発プロセスに統合することで、クリエイターはオブジェクト指向プログラミングに伴う従来の障壁を克服し、よりスムーズで効率的なワークフローを実現できます。Unity DOTS によって強化された Unity エンジンは、ゲーム デザインの可能性の限界を押し広げることを目指す開発者にとって、さらに強力なプラットフォームになります。

さらに、Unity DOTS システムは、Unity が技術の進歩に適応する先見性を示しており、Unity のプラットフォームで開発されたゲームが、その実行ハードウェアを最大限に活用できるようにします。Unity は DOTS フレームワークの改良と拡張を続け、開発者の現在の要求に応えるだけでなく、ゲーム技術の進化を予測するシステムを提供することで、ゲーム開発業界のリーダーとしての地位を固めています。

まとめと考察

UnityUnrealはゲームエンジンの2トップですが、いよいよ従来のオブジェクト指向一辺倒であった状況から脱し、データ・関数型プログラミングへ移行しはじめています。

Unrealは関数型言語HaskellをベースにMaxVerseという新しい関数型言語をフレームワークへ統合する予定らしいです。

UE6にはフォートナイト用の言語「Verse」が導入される?GDC 2024のVerse講演から見るアンリアルエンジンの今後
2024.04.22

image

MaxVerseは、Haskellベースの言語として開発中。リリース時には講演時点より10倍のパフォーマンス向上を実現し、Webブラウザ上で実行できる状態を予定しているとのこと。


https://zenn.dev/ken_okabe/books/functional-programming-from-scratch-1/viewer/fp-languages

でも、Unreal Verseについて解説しています。


オブジェクト指向 — 1兆ドルの大災害

オブジェクト指向の欠陥と関数型プログラミングへ移行の推奨は従前より何度も主張されてきていました。

https://medium.com/better-programming/object-oriented-programming-the-trillion-dollar-disaster-92a4b666c7c7

こういう記事はあくまでひとりの技術者によるブロク記事であり、いくら正当な主張であっても、従来のオブジェクト指向プログラマーには、おそらくサンクコストによる認知バイアス、もっと言えば彼らの「信仰心」により聞き入れられなかった経緯があります。

しかし、「現実的」なアプリケーションであるゲームエンジンの2トップがそろってこのようにオブジェクト指向を実質否定し関数型プログラミングへ積極的に移行しようとするトレンドは彼らにとってもかなり重い事実となるはずです。


Discussion