ぐーるらいふ

底辺。

【Unity】 DOTS(ECS)をWebGLで使う場合は思った以上にパフォーマンス出ないよって話

DOTSをWebGLで...だと?

またまたUnityの話題。DOTS(ECS)のお話だよ。


Unity1weekが近くなってきて、
「流行りのDOTSでいっちょ神ゲー作ってやろう」
なんて考えてるそこのキミに見てほしいです。

結論から言うとWebGL出力だとJob , Burst使っても
思ったよりもパフォーマンス出ないよ、って話です。

実装について

今回の調査では
「オブジェクトを大量に表示しつつRotateだけ行う」
という簡単な動きだけで計測してます。

細かい実装はほぼこれなんでそっちを読んでもらい、RotateSystemだけ載せます。

ghoul-life.hatenablog.com

#define USE_JOB
#define USE_BURST
#if USE_BURST
using Unity.Burst;
#endif
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

#if !USE_JOB

public class RotateSystem : ComponentSystem
{
    protected override void OnUpdate()
    {
        var deltaTime = UnityEngine.Time.deltaTime;
        Entities.ForEach((ref Rotation rotation, ref RotateSpeedComponent rotateSpeedComponent) =>
        {
            rotateSpeedComponent._rotationAngle += rotateSpeedComponent._rotationSpeed * deltaTime;

            rotation.Value = quaternion.RotateY(rotateSpeedComponent._rotationAngle);

            if (rotateSpeedComponent._rotationAngle >= 360.0f)
            {
                rotateSpeedComponent._rotationAngle -= 360.0f;
            }
        });
    }
}
#endif

#if USE_JOB
public class RotateSystem : JobComponentSystem
{
#if USE_BURST
    [BurstCompile]
#endif
    struct RotateJob : IJobForEach<Rotation,RotateSpeedComponent>
    {
        public float deltaTime;

        public void Execute(ref Rotation rotation, ref RotateSpeedComponent rotateSpeedComponent)
        {
            rotateSpeedComponent._rotationAngle += rotateSpeedComponent._rotationSpeed * deltaTime;

            rotation.Value = quaternion.RotateY(rotateSpeedComponent._rotationAngle);

            if (rotateSpeedComponent._rotationAngle >= 360.0f)
            {
                rotateSpeedComponent._rotationAngle -= 360.0f;
            }
        }
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var job = new RotateJob() { deltaTime = UnityEngine.Time.deltaTime };
        return job.Schedule(this, inputDeps);
    }
}
#endif

(雑にdefineでJob、Burstの使う使わないを切り替えれるようにしてます。
実際に使うときはこんなん作らないからね。適当です。)

PCでEntityのみの場合(50000object)

まず、PCでEntity + ComponentSystemだけで50000Object出すと
このぐらいのパフォーマンスになります。

vimeo.com

(13~14FPS)

PCでフルセットの場合(50000object)

次にJobSystemとBurstコンパイラを利用した形式に変えて
再度計測してみます。するとこのぐらいのパフォーマンスになります。

vimeo.com
(24~25FPS)


10も上がった!!
いいですね、このぐらい目に見えて良くなると実装しがいがあるというもの。

WebGLはどうなの?

unity1weekで使いたい、サクッとgithubで公開したい、
といった方はWebGLでの出力が候補になります。
50000objectだと重すぎて動かなかったので、10000objectまで下げてます。
また、ブラウザはFireFoxで見てます。

WebGLでEntityのみ(10000obj)

vimeo.com
12FPS

オブジェクト数下げてもこれ。
うーん、苦しいです。最小構成でこれでは
実際のゲームでは使い物にならないでしょう。

WebGLでフルセット(10000obj)

vimeo.com
15FPS

JobSystemとBurstコンパイラを利用した形式に変えてみましたが微増。
これでも苦しい...。

結論として

WebGLでDOTS使いたいなら5000object程度に留めておいた方が良さそうです。

過去作った全てを破壊したいUnityちゃん、というゲームでも
1000object以下で収まるように調整してました。
(WebGLではあれ以上街を広げられない)

unityroom.com

それでも3倍はいけるというDOTSの実力には脱帽ですね。
誰かunity1weekでドドドッと襲いかかってくるゾンビを
ひたすら撃ちまくるゲームとか作ってください。

補足として

偉大な先駆者maoさんがすでにunity1weekでDOTSにチャレンジされています。

unityroom.com

早速遊んでみたのですが僕の環境ではゲームをブラウザで開くと
まともに動かずガクガクで...。
githubにある動画ほどのスムーズさも見えず...。
もしかして自分のPCが弱いのでしょうか?

このぐらいまともに遊べるぜ!って人PCスペック教えてください...。

ソースまで公開されてます!神さま〜〜!
github.com

さらに補足

スーギ・ノウコ自治区さんに教えていただきました!
やはりWebGLは現時点でSIMDとマルチスレッドをサポートしていない様子。

またWebAssemblyの情報まで!

ありがとうございます〜。