[Unity DOTS]気になった部分のメモ書き

はじめに

特に使いこなせているわけではありませんが、サンプルなどを使ってみた上で気になった部分などをまとめて後で読み返せるようにしておくだけのメモ書きレベルです。
間違っている箇所があれば教えてください。

サンプルのリポジトリ

Entityのドキュメント


シーンごとに実行されるシステムを変更する

RequireForUpdate<T>() を使用すると実現できる。指定した型のコンポーネントがない限り実行されないため、そのシーンごとに固有のコンポーネントを指定してあげる。

動的バッファー コンポーネント作成時はInternalBufferCapacityを指定する

容量が足りなくなった際のメモリ確保を行う回数が少なくなる

NoAliasを指定すると速度が上がる

多分使うことはない

コンポーネントの検索方法

SystemAPI.Query と GetEntityQuery の2通りぐらいしか使われないと思う。
基本的には SystemAPI.Query で事足りる。コンポーネントの数を調べたいときには GetEntityQuery を使用した方が楽。
Entities.ForEachは古くなった。

Instantiateしてもオブジェクトが表示されない

LocalTransform などの位置に関するコンポーネントも指定しておかないといけない(遠くにあるだけ?)

ジョブに作業対象のコンポーネントを指定する方法

Executeの引数で指定
IJobEntityなら引数にQueryを指定してあげる
ComponentLookupを使う
の3つぐらい?

EntityからそのEntityが持っているコンポーネントにアクセスする方法

GetComponentLookupを使う

依存関係のジョブの実行を待つ

state.CompleteDependency();

デバッグで使えるウインドウ

アーキタイプウインドウ
コンポーネントウインドウ
システムウインドウ

Blobはどこで使うのか

AnimationClip、CollisionMesh、CurveDataなどの大量のデータに対して使うと処理が早くなるみたい。

ジョブ実行の種類

Run メインスレッド
Schedule 1スレッド(メインスレッドではない)
ScheduleParallel 複数スレッド

同期点の原因

チャンクデータ内のエンティティコンポーネントのレイアウトに対する変更エンティティの作成または破棄
コンポーネントの追加または削除
共有コンポーネントの値の変更

SystemAPI.QueryでEntityを扱う場合

foreach(var (block, entity) in SystemAPI.Query<Block>().WithEntityAccess())
        {
            ecb.DestroyEntity(entity);
        }

WithEntityAccessが必要

BeginSimulationEntityCommandBufferSystem と EndSimulationEntityCommandBufferSystem

エンティティの追加はBegin 削除はEndがいいっぽい。
とはいえ処理に大きな問題がおこることはないと思う。実行順が意識できていれば問題ない

配列をベイクする

NaitiveArrayを使う。アロケーターの指定も必要。(基本的に永続的な指定で良いと思う)

LinkedEntityGroupの使い道

子のオブジェクトをまとめて指定できるグループとなるみたい

安全性のチェックは最終的に外す

タスクバーのジョブからBurstの安全チェックをオフにできる。開発が終わればオフにした方が早い

動的バッファの確保方法

GetBufferLookupを使う

プレハブの数に注意

プレハブ用のコンポーネントが存在するため、最悪プレハブの数だけチャンクが存在することになる。プレハブからオブジェクトを作成する際にそのコンポーネントは削除されるらしい。

普段からMathfじゃなくmathを使うべきか

特にDOTS内でないならMathfでも問題ない。(それでもC#自体のMathを使った方が軽いって話があった気がする)

コンポーネントの値が変更したときにBakeしなおしたい

DependsOnを使う

WorldTransformを書き換えても位置が移動しない

WorldTransformは書き換えても何も起こらない。LocalTransformを変更すること

EntityのIndexを取得したい

public void Execute([EntityIndexInQuery] int entityInQueryIndex)

チャンクのIndexとチャンク内のIndexからEntityIndexInQueryを作る方法もあるみたい。どちらでも問題ないと思う。

共有コンポーネントの有用性

クエリが特定の共有コンポーネントの値をフィルター処理できる。
また、メッシュ、マテリアルなどが同一のコンポーネントはまとまっていた方が処理が早いという考え方っぽい。
DynamicBufferの代わりとして使えたりもするが効率が悪くなるらしい。

カスタムシェーダーグラフでインスタンスごとに色を変えたい

これで解決した
How to change entity's color by code in ECS - Unity Forum

Jobs, Burst

Burstが早くなる理由

ベクトル(配列みたいなもの)に対しての処理を最適化するみたい。パイプラインとかそのあたりの話になると思う。
後はアンマネージドなものしか扱わないから。

長時間のジョブ実行は注意

無駄に長くなるらしい。細かく分けたりスレッドを減らす(多分そのスレッドを特定のジョブ専用とする意味)必要がある。

Physics

重力の適用

com.unity.physics をインポートして Phisics Body をアタッチする

接触判定のレイヤーみたいなやつの設定

Physics ShapeのBelong Toがそのオブジェクトを所属させるもの。
Collides Withが接触していいやつになる。

Collisionの設定

// 同様にこの構造体を持つ構造体にも必要
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(PhysicsSystemGroup))]
[BurstCompile]
    struct TriggerGravityFactorJob : ITriggerEventsJob
    {
        public EntityCommandBuffer ECB;
        [ReadOnly] public ComponentLookup<TriggerGravityFactor> TriggerGravityFactorGroup;
        public ComponentLookup<PhysicsGravityFactor> PhysicsGravityFactorGroup;
        public ComponentLookup<PhysicsVelocity> PhysicsVelocityGroup;

        public void Execute(TriggerEvent triggerEvent)
        {
            Entity entityA = triggerEvent.EntityA;
            Entity entityB = triggerEvent.EntityB;

            bool isBodyATrigger = TriggerGravityFactorGroup.HasComponent(entityA);
            ECB.DestroyEntity(isBodyATrigger ? entityB : entityA);
        }
    }

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
で物理演算時に(FixedUpdate単位)実行してくれる

[UpdateAfter(typeof(PhysicsSystemGroup))]
を入れないと物理演算が終わる前に結果にアクセスする可能性がある

エラー系

ArgumentException: System.ArgumentException: A component with type:{0} has not been added to the entity.

エンティティに該当コンポーネントがないのにSet Componentを呼び出したりした場合。コンポーネントをつけてあげれば解決する。

InvalidOperationException: The previously scheduled job SafeZoneJob writes to the ComponentLookup<Unity.Collections.NativeText.ReadOnly> SafeZoneJob.JobData.__Unity_Transforms_TransformAspectTypeHandle.m_WorldTransformCth. You must call JobHandle.Complete() on the job SafeZoneJob, before you can read from the ComponentLookup<Unity.Collections.NativeText.ReadOnly> safely.

ジョブが終わっていないことが原因。対応方法はいくつかあると思うが、依存関係を定義して、ジョブの実行終了まで待ってあげると良いっぽい。

InvalidOperationException: Attempted to access the ComponentLookup<Unity.Collections.NativeText.ReadOnly> TestJob.JobData.WorldTransformLookup which has been invalidated by a structural change.

WorldTransformLookupをUpdateしてないことが原因

ArgumentException: All entities created using EntityCommandBuffer.CreateEntity must be realized via playback(). One of the entities is still deferred (Index: -1).

多分ECBで作成するようにしたが、まだECB内のコマンドが実行されてないにもかかわらず、Entityにアクセスしたときにでてるっぽい。

この記事が気に入ったらサポートをしてみませんか?