はじめに
ネットサーフィンをしていたところ、以下の動画を見つけました。
DOTS
を利用しているUnity Physics
ですが、これほどまで違うのかと感じます。
ただ私はまだ信用していません。なぜならまだ自分で試していないからです。
見せてもらいましょう、Unity Physics
の力とやらを。
環境
MacBook Pro(16-inch, 2019)
2.6 GHz 6コア Intel Core i7
16 GB 2667 MHz DDR4
Intel UHD Graphics 630 1536 MB
Unity 2020.3.1.18f1
Unity Physics Version 0.6.0-preview.3
Hybrid Renderer Version 0.11.0-preview.44
Universal RP Version 10.6.0
プロジェクトのビルド:Mono*1
ログ出力:なし
補足
Hybrid RendererのV2を利用するには色々と操作しなければいけません。(結構めんどくさい&忘れがち...)
Package Manager
からインストールしただけではV1
が適応されている上、URP
のバージョンが8.0.0
固定だったりとかなり厄介です。
以下の公式に手順が載ってるので参照してみてください。
docs.unity3d.com
実験
Cube
をどんどん生成していき、30fps以上を維持できなくなるまでの最大のオブジェクト数を調べます。
またエディタ上だとUnity Physics
は遅いとの噂なので、Mac
向けにビルドして計測しました。
【Unity】新しい物理演算、Unity Physicsについて - テラシュールブログ
加えて毎フレームInstantiate
をしてしまっているのでその処理時間も含まれてしまったりと色々と適当測定ですが、許してください。
床の準備
動く物体の準備
インスタンス生成のスクリプト
まずはDOTS
を使わないいつものパターン。
public class GameManager : MonoBehaviour { [SerializeField] private GameObject prefab; [SerializeField] private Text textObj; private float _time; private long _count; private long _maxCount; private FPSCounter _fpsCounter; private void Start() { Application.targetFrameRate = 60; _fpsCounter = new FPSCounter(4); } private void Update() { _time += Time.unscaledDeltaTime; _fpsCounter.Update(); if (_fpsCounter.FPS >= 30 && _count != _maxCount) _maxCount = _count; if (_time < 0.005f) return; Instantiate(prefab); _time = 0; _count++; textObj.text = $"FPS : {_fpsCounter.FPS}\nCount : {_count}\nMaxCount : {_maxCount}"; } }
次にDOTS
パターン。
public class GameManagerDOTS : MonoBehaviour { [SerializeField] private GameObject prefab; [SerializeField] private Text textObj; private Entity _entityPrefab; private EntityManager _entityManager; private BlobAssetStore _blobAssetStore; private float _time; private long _count; private long _maxCount; private FPSCounter _fpsCounter; private void Start() { Application.targetFrameRate = 60; _fpsCounter = new FPSCounter(4); // プレハブをEntityに変換 _blobAssetStore = new BlobAssetStore(); _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; var setting = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, _blobAssetStore); _entityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(prefab, setting); } private void Update() { _time += Time.unscaledDeltaTime; _fpsCounter.Update(); if (_fpsCounter.FPS >= 30 && _count != _maxCount) _maxCount = _count; if (_time < 0.005f) return; _entityManager.Instantiate(_entityPrefab); _time = 0; _count++; textObj.text = $"FPS : {_fpsCounter.FPS}\nCount : {_count}\nMaxCount : {_maxCount}"; } private void OnDestroy() { _blobAssetStore.Dispose(); } }
FPS
の測定は以下のコードを利用させていただきました。
【Unity】FPS を計測するスクリプト - コガネブログ
補足
以前までPrefab
をEntity
に変換する際に以下のコードで動作していたのですが、エラーが出てくるようになっていまいました。
var setting = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, null);
ArgumentNullException: A valid BlobAssetStore must be passed to construct a BlobAssetComputationContext Parameter name: blobAssetStore
BlobAssetStore
なるものを生成して渡してあげればエラーは消えるようです。
Cant Convert GameObject to Entity in 0.3 version - Unity Forum
実験結果
種類 | MaxCount |
---|---|
いつもの | 7993 |
Unity Physics | 7023 |
......ん?
考察
まさかのUnity Physics
を利用しない方がFPSを保つことができていました。
ただ原因はこれまで書いていてちょくちょくコメントしていた箇所だと思います。
Update
内のオブジェクト生成の処理IL2CPP
を利用していない
さいごに
さすがにこの結果はまずいので、また条件を変えながら実験してみたいと思います。
というか私自身DOTS
の理解が浅く上手に活用できていない可能性大なので、なにかありましたらコメント等で教えていただけると嬉しいです。
ではまた。
参考
Getting started with DOTS: Scripting Pong (Tutorial) - YouTube
How many Rigidbodies can Unity support ? [2020 DOTS Edition] - YouTube
Hybrid Renderer overview | Hybrid Renderer | 0.11.0-preview.44
Introduction to Unity Physics | Package Manager UI website
*1:IL2CPPで実験したかったのですが、アプリを起動するとすぐにクラッシュしてしまったため。あとでIL2CPPで検証したいです。