Search Unity

この記事は、私たちの新しい Data-Oriented Tech Stack(DOTS)に関するいくつかのブログ記事のうちの 1 つです。私たちの現状と今後の方向性について説明します。

前回の記事では、今後の Unity の低水準レイヤーの基本的なテクノロジーとして HPC# と Burst について説明しました。ここでは、私たちのスタックのこのレベルを「ゲームエンジンのエンジン」と呼びたいと思います。このスタックを使えば、誰でもゲームエンジンを作成することができます。私たちには作成できる能力があり、その意思があります。読者の皆さんも同じです。私たちのゲームエンジンに不満がある場合は、自作したり、好みに合わせて変更したりしてください。

Unity のコンポーネントシステム

私たちが次に作ろうとしているレイヤーは、新しいコンポーネントシステムです。Unity の中心には常に、コンポーネントの概念があります。Rigidbody コンポーネントをゲームオブジェクトに追加すると、ゲームオブジェクトは落下するようになります。Light コンポーネントをゲームオブジェクトに追加すると、光を放出するようになります。AudioEmitter コンポーネントをゲームオブジェクトに追加すると、音を出すようになります。

これは、プログラマーにとってもプログラマー以外の人にとっても、非常に自然な発想であり、直感的な UI を簡単に作ることができます。この発想は、非常に驚くべきことにとてもよく成熟しています。その成熟度合いは、そのまま利用し続けたいほどです。

しかし、Unity のコンポーネントシステムの実装方法はそれほど成熟していません。コンポーネントシステムは、オブジェクト指向の考え方で開発されました。コンポーネントもゲームオブジェクトも、「重い C++」オブジェクトです。これらを作成/破壊するには、id->objectpointer のグローバルリストを変更するために、ミューテックスロックが必要となります。すべてのゲームオブジェクトには名前があります。それぞれが、C++ のオブジェクトを指す C# ラッパーオブジェクトを取得します。その C# オブジェクトは、メモリ内であればどこでも存在する可能性があります。また、C++ オブジェクトもメモリ内であればどこでも存在する可能性があります。キャッシュミスがたくさん発生します。私たちはこのような症状をできる限り軽減しようと試みていますが、一方で、開発者にできることは限られています。

データ指向の考え方をすると、もっとよい対応ができます。Unity の新しいコンポーネントシステムでは、優れた特性をユーザーから見て同じように維持しながら(Rigidbody コンポーネントを追加すると物が落下する)、素晴らしいパフォーマンスと並列処理も実現します。

この新しいコンポーネントシステムが、Unity の Entity Component System(ECS)です。非常に大まかに言うと、現在ゲームオブジェクトを使って行っていることを、新しいシステムではエンティティを使用して行います。コンポーネントは引き続きコンポーネントと呼びます。では、何が違うのでしょうか。データのレイアウトです。

一般的なデータアクセスパターンをいくつか見てみましょう
Unity で従来の方法を使って一般的なコンポーネントを記述すると、以下のようになるでしょう。


このパターンは繰り返し使われます。あるコンポーネントは、同じゲームオブジェクト上でその他のコンポーネントを 1 つ以上検索し、そのコンポーネントの値の読み取り/書き込みを行わければなりません。

このコードには多くの誤りがあります。

  • Update() メソッドが 1 つの Orbit コンポーネントに対して呼び出されます。次の Update() は、まったく別のコンポーネントに対して呼び出される場合があります。すると、このコードはキャッシュから削除され、次回は、別の Orbit コンポーネントに対してこのフレームが実行される可能性があります。
  • Update() は GetComponent() を使用してその Rigidbody を検索する必要があります(代わりにそれをキャッシュすることもできますが、その場合は破壊していない Rigidbody コンポーネントに留意する必要があります)。
  • 操作中の他のコンポーネントがメモリ内のまったく別の場所にあります。

ECS で使用するデータレイアウトでは、これが非常によく見られるパターンであることを認識し、メモリのレイアウトを最適化してこのような操作を高速化します。

ECS のデータレイアウト

ECS は、まったく同じ一連のコンポーネントをメモリ内に集めたエンティティすべてをグループ化します。そのようなセットをアーキタイプと呼びます。アーキタイプの一例は、「Position & Velocity & Rigidbody & Collider」です。ECS によるメモリ割り当ては、16k のチャンク単位で行われます。各チャンクに含まれるのは、単一のアーキタイプのエンティティのコンポーネントデータだけです。

ECS では、実行時に Update メソッドを使用して操作対象の他のコンポーネントを検索するのではなく、Orbit インスタンスごとに次のように静的に宣言すればかまいません。「Velocity、Rigidbody、および Orbit コンポーネントを持つすべてのエンティティに対して、ある操作を実行したい」と。そのようなエンティティを見つけるには、特定の「コンポーネント検索クエリ」に一致するすべてのアーキタイプを検出するだけです。各アーキタイプには、そのアーキタイプのエンティティが格納されているチャンクのリストがあります。そのチャンクをすべてループ処理し、各チャンク内で密度の高いメモリに対して線形ループを実行して、コンポーネントデータの読み取りと書き込みを行います。各エンティティで同じコードを実行するこの線形ループは、Burst でベクトル化を行う格好の対象にもなります。

多くの場合、このプロセスは当然ながら複数のジョブに分割することができ、ECS コンポーネントを操作するコードは 100% 近いコア使用率で実行されます。

上記の処理はすべて ECS によって行われるため、開発者が行う必要があるのは、各エンティティで実行するコードの指定だけです(必要に応じて、チャンクの反復処理を手動で行うこともできます)。

エンティティでコンポーネントを追加/削除したりすると、アーキタイプが切り替わります。該当するコンポーネントを現在のチャンクから新しいアーキタイプのチャンクに移動し、前のチャンクの最後のエンティティをもう一度スワップして「穴埋め」します。

ECS では、コンポーネントデータを使用する目的も静的に宣言します(ReadOnly または ReadWrite)。Position コンポーネントから読み取りしか行わないことを約束する(この約束は検証済み)ことで、ECS はジョブをより効率的にスケジュールできます。Position コンポーネントから読み取りを行う他のジョブも、待機しなくてよくなります。

このデータレイアウトによって、長年にわたって不満であった、ロード時間とシリアル化パフォーマンスに関しても対処できるようになります。大きなシーンの ECS データをロード/ストリーミングするのは、ディスクから raw バイトをロードしてそのまま使用するのとほとんど違いがありません。

『Megacity』デモがスマートフォンに数秒でロードされるのはこのためです。

うれしい「アクシデント」

エンティティでは、現在ゲームオブジェクトで行える処理と同じ処理が可能です。さらに、エンティティは軽量なので、ゲームオブジェクトよりもできることが広がります。実際のところ、エンティティとは何なのでしょうか。このブログ記事のドラフトでは当初、「エンティティはチャンクに格納されます」と説明していましたが、後から「エンティティのコンポーネントデータはチャンクに格納されます」に変更しました。これは、エンティティがたった 32 ビットの整数であることをはっきりさせるうえで、重要な違いです。エンティティに関して、そのコンポーネントのデータ以外に格納したり、割り当てたりするものはありません。エンティティは非常に負荷が軽いので、ゲームオブジェクトが適していなかったシナリオに利用することができます。たとえば、パーティクルシステムの個々のパーティクルにエンティティを使用するようなシナリオです。

HPC#、Burst、ECS。素晴らしいが、ゲームエンジンはどこに?

次に構築する必要があるレイヤーは、非常に巨大です。その「ゲームエンジン」レイヤーは、「レンダラー」、「物理演算」、「ネットワーク」、「入力」、「アニメーション」などの機能で構成されます。ざっくり言えば、これが私たちの現状です。それら構成要素に取り組み始めていますが、それらを一晩で準備できるわけはありません。

残念に思われるかもしれません。ある意味ではそのとおりですが、別の意味では違います。ECS と、その上に構築されるすべてのものは C# で記述されているため、従来の Unity 内で実行することができます。ECS は Unity 内で実行されるので、ECS 以前の機能を使用する ECS コンポーネントを記述することができます。現時点では、純粋な ECS メッシュ描画システムはありません。しかし、純粋な ECS バージョンが配布されるまでの間、ECS より前の Graphics.DrawMeshIndirect API を実装として使用する ECS MeshRenderSystem を記述することができます。『Megacity』デモでは、まさにこの手法を利用しています。純粋な ECS システムによって、ロード/ストリーミング/カリング/LOD 処理/アニメーションは行われますが、最終的な描画は行われません。

そこで、うまく組み合わせることで対処できます。この対処方法の利点は、すべてのサブシステムの純粋な ECS バージョンが配布されるのを待たなくても、Burst によるコード生成と、ゲームコードでの ECS のパフォーマンスのメリットをすぐに享受できることです。一方、欠点としては、ECS はまだ過渡期にあるため、「2 つの異なる世界を繋ぎ合わせて使用している」というちぐはぐさを感じる可能性があります。

私たちは、ECS HPC# サブシステムのソースコードすべてをパッケージに含めて配布する予定です。これにより、各サブシステムを調査、デバッグ、変更できるほか、どのサブシステムをいつアップグレードするかをより詳細に制御できます。たとえば、Physics サブシステムパッケージだけをアップグレードして、他のサブシステムはアップグレードしないようにできます。

ゲームオブジェクトの今後

ゲームオブジェクトはなくなりません。ゲームオブジェクトを利用して、今後もずっと素晴らしいゲームを配布することができます。その基本事項はどこにも行きません。

変わるのは、Unity の改善のためにエネルギーを注ぐ先です。徐々に、ゲームオブジェクトの世界ではなく、ECS の世界だけにエネルギーが注がれるようになります。

API の使い勝手/定型コード

ECS について説明するときによく指摘される、文句を言いたいのも当然な点は、タイピングする量が非常に多いことです。開発者が、達成しようとしている目的を果たすには、さまざまな定型コードを入力する必要があります。

ほとんどの定型コードを不要にしたり、開発者が意図を表現しやすくしたりするために、多数の改善が行われる予定です。私たちが現在注力している対象は基本的なパフォーマンスであるため、予定されている改善の多くはまだ実装していません。しかし、ECS ゲームコードにたくさんの定型コードが含まれていたり、MonoBehaviour を記述するよりもかなり多くの手間がかかったりしてよい理由はないと考えています。

Project Tiny には、先述の改善事項のいくつかがすでに実装されています(ラムダベースのイテレーション API など)。それについて紹介しましょう。

Project Tiny の ECS との関係について

Project Tiny は、このブログ記事で取り上げているのと同じ C# ECS をベースにして配布されます。私たちにとって Project Tiny は、以下の点で ECS の大きなマイルストーンとなります。

  • 完全な ECS 専用の環境で実行できる。新しいプレイヤーは過去の環境から何の影響も受けません。
  • 上記の事実は、これが純粋な ECS でもあり、実際の(Tiny)ゲームに必要な ECS サブシステムすべてを搭載する必要があることを意味する。
  • Project Tiny のエディターサポートを、Tiny Mode だけでなく、あらゆる ECS シナリオの Entity 編集に導入する予定である。

開発に加わりませんか?

Unity では、DOTS スタックに関するさまざまな職務で人材を募集しています。特に、バーバンクとコペンハーゲンのオフィスで勤務できる方の応募をお待ちしています。詳しくは、careers.unity.com をご覧ください。

Unity Entity Component System と C# Job System フォーラムにもぜひ参加して、実験的機能やプレビュー機能に関するフィードバックをお寄せください。また、フォーラムでは、そのような機能に関する情報を入手することもできます。

25 コメント

コメントの配信登録

コメント受付を終了しました。

  1. Philipp Lenssen

    4月 12, 2019 9:17 pm

    And one day, there will be machine-learning intelligence which converts your GameObjects into Entities…

    pleease…

    In the meantime, super excited to try this for new projects in the future. I reckon it will get more and more usable from a “developer-consumer” point of view. After all, Unity’s ease of use is one of its big appeals. Some of the recent tutorials on DOTS have been heavily to-the-metal-tech focused, but in my projects I love to think about… you know… robots, unicorns, VR gestures, chat, and whatever else is important for the actual experience.

    Godspeed!

  2. can this be used on commercial projects ?

  3. Please, make it possible to supply Mesh with Native Arrays. Copying arrays around is very annoying.

  4. Firstly thanks for this and I hope more posts like this are done in Unity’s blog. Back then when Lucas was still a Unity customer, I was excited to read every post in unity’s blog and even the back then technical evalgelist of Unity’s posts were much more useful compared to some of what we see on the blog these days.
    He was evangelizing too and even back thens posts were being done which they had other goals than educating the reader about deep technical things but they had that nameless type of quality which is lost now.

    On ECS stuff, the FPS sample helped a lot and posts describing how regular things are done in ECS or maybe writing a 100 page PDF tutorial like what you guys did for lerpz for ECS samples probably would help many.

    For the FPS sample and ECS in general I put nights of my two weeks to watch all videos and read almost all code of the sample but not always you have such time and not everyone can learn like that.

  5. Dude Dudette

    3月 11, 2019 9:21 am

    You are doing a terrible job of introducing a paradigm-shift

    1. Dude Fugges Duddette

      3月 15, 2019 11:01 pm

      You are doing a terrible job of expressing your criticism of this piece

  6. Thank you for the article! Now I understand ECS more. Clarity matters.

  7. So would you gays publish the whole MegaCity project?

  8. Setriakor Nyomi

    3月 9, 2019 7:53 pm

    Having been around to witness the growing pains that came with the IL2CPP transition, I have complete faith that you can pull this off. Although it feels a bit like comparing apples to oranges, I can draw some parallels especially around the time and resources it is going to take to have a mature version of the ECS family of technologies being similar IL2CPP’s.

    I for one cannot wait to start using pure ECS for everything, but I know that’s still a pretty long way off. I’m still excited to see all this progress though, and would like to see these posts once every week or so. Also like that parts of the engine are being ported to HPC# and will be open sourced. Keep up the good work!

  9. Unity 5.6.7 not support android 9 (API level 28) ?

  10. As a creative, not a coder, i feel a little bit better about ECS after this blog post. I just don’t want to see Unity go the way of Flash, which alienated artists and creatives with the “superior” but verbose AS3, and a structure that was more logical, but deterred fast artistic iteration. I hope Unity remains accessible to designers and artists without an engineering or professional coding background. That said, the idea behind ECS – building complexity from increasingly atomic components – seems like a good idea.

  11. Alejandro Castán

    3月 8, 2019 11:59 pm

    Hi Lucas. First of all, Great Post!!! .On the other hand, I am interested in learning ECS Puré and for it, I would like to learn with Proyect Tiny. Is this proyect made in ECS Puré? Finally and since I am very excited to get the Megacity demo, for ir, Do You think if it could be avalable in the next GDC? Thanks for your time. Alejandro

  12. Blog post blocks a certain user. WTF!

  13. Alan Mattano

    3月 8, 2019 3:42 pm

    Lucas Meijer, If you allow me to give you a suggestion here since a dedicated feedback solution is coming: Give you margins. In the car industry, we start designing and making a model with 10 years in advance. Perhaps Unity 2019 should have been called Unity 2021 to make it clearer to new users that it is a WIP software. So (as for example) this October 2019 you release Unity 2020LTS ready (ower Unity 2018LTS) and on January 2020, the Unity2020.4.18f1 LTS. In this way, the LTD arrives when the year starts (and not a year or two later). So that new beginners with no experience can look to a lot of tutorials in YouTube and do not experiment with a WIP software in the evolution phase creating noise on the forum. Experts feel comfortable creating the future. If you jump U2020 and 21 making U2022 for branding purpose we will miss the nice numbers 2020 but I think users can understand that. Is just a feeling. Thank you and your awesome team.

    1. While Lucas probably has no input on product naming, I agree with some of your points. It does feel like newcomers should be directed to an LTS release, and it would make more sense to name the software for the year they hit LTS.

      So, in my opinion, “Unity 2017 LTS” should be “Unity 2018” and “Unity 2019” should be “Unity 2020 Preview”. Experts, as you said, are often comfortable creating with the newest features, especially when it often takes over a year to develop even a modest game — Starting with 2020 Preview means you’ll likely ship after 2020 releases in its final, LTS state. Maybe they even drop “Preview” during the 4th quarter of 2019 — the key is having a pool of community knowledge on top of updated tutorials when this happens.

  14. Nice post! It is great to see that you are working on ECS! These kind of blog are a must read for me as a programmer thank you!

  15. Peter Mullins

    3月 8, 2019 2:01 pm

    The problem is that many time pass and the ECS system is not ready.

  16. A lot of marketing and great promises. Almost 2 years has been passed from initial presentations of ecs and your users still have nothing more than empty talking how great it could be.

    1. Wasn’t it announced in 2018?

      1. Nope. They showed massive battle scene in 2017. It was based on ECS and Burst compiler back then. It’s 2019, and we are still far away from production ready DOTS. We use burst in our shipped product, but there is a lot of missing API for NativeArrays. Only textures are possible to read/write to NA. Other parts of engine are still based on managed types. Under the hood, they call C++ functions with pointers to these arrays, so why we still can’t update meshes with NA? Why we can’t call Graphics API with NA? It seems like a small change in engine API with huge positive impact for ECS development. Maybe they create whole new API for ECS, and they don’t want people to base their games on older API, but engine is constantly updated with old C# managed style. Just look at SRP.

  17. > Update() has to use GetComponent() to go and find its Rigidbody. (It could be cached instead, but then you have to be careful about the Rigidbody component not being destroyed).

    In what instance would rigidbody not be destroyed? If you destroy the gameobject with the script, cached link, and rigidbody on you are not fine? Using GetComponent() has been a no-no in discussions for a long time

    1. He means not being destroyed externally I think.

  18. “Entity is just a 32-bit integer” => Entity is just two 32-bit integer

    To be precise :p

  19. Sergey Klimenko

    3月 8, 2019 10:17 am

    Great as expected :)