Unity DOTS 入門 (2) - エンティティの生成
Unity DOTS の練習として、「エンティティ」の生成を行います。
・Unity 2019.3.14.f1
・Entities 0.11.1
1. DOTSパッケージのインストール
「Unity DOTS 入門 (1)」と同様。
2. エンティティの生成
スクリプト「Spawner」を作成し、「エンティティ」を生成します。
(1) Hierarchyウィンドウの「+ → Create Empty」で空のゲームオブジェクトを作成し、名前に「Spawner」を指定。
(2) 「Spawner」にスクリプト「Spawner」を追加し、以下のように編集。
using Unity.Entities;
using UnityEngine;
public class Spawner : MonoBehaviour
{
void Start()
{
EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
entityManager.CreateEntity();
}
}
「World.DefaultGameObjectInjectionWorld.EntityManager」でデフォルトワールドの「EntityManager」を取得し、CreateEntity()で「エンティティ」を生成しています。
(3) 実行。
メニュー「Window → Analysis → Entity Debugger」で生成した「エンティティ」の存在を確認できます。Inspectorウィンドウに表示される「エンティティ」の属性は、コンポーネントを持ってないので空になります。
3. コンポーネントの追加
「アーキタイプ」(コンポーネント種別セット)を使って、「エンティティ」に「コンポーネント」を追加します。
(1) スクリプト「Spawner」を以下のように編集。
using Unity.Entities;
using UnityEngine;
using Unity.Transforms;
using Unity.Rendering;
using Unity.Mathematics;
public class Spawner : MonoBehaviour
{
void Start()
{
EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
EntityArchetype archetype = entityManager.CreateArchetype(
typeof(Translation),
typeof(Rotation),
typeof(RenderMesh),
typeof(RenderBounds),
typeof(LocalToWorld));
entityManager.CreateEntity(archetype);
}
}
「アーキタイプ」は「コンポーネント種別セット」です。entityManager.CreateArchetype()で生成します。
今回は、以下の「コンポーネント種別」を設定しています。
・Translation : 位置
・Rotation : 回転
・RenderMesh : レンダリングメッシュ
・RenderBounds : レンダリング領域
・LocalToWorld : ローカル座標
CreateEntity()の引数に「アーキタイプ」を渡すことで、「コンポーネント種別セット」に含まれる「コンポーネント」を保持する「エンティティ」が生成されます。
(2) 実行。
「Entity Debugger」で「エンティティ」を選択することで、Inspectorウィンドウに追加された「コンポーネント」が表示されます。値は初期化されていません。
4. コンポーネントのデータの設定
「コンポーネント」のデータを設定して、立方体を表示します。
(1) スクリプト「Spawner」を以下のように編集。
using Unity.Entities;
using UnityEngine;
using Unity.Transforms;
using Unity.Rendering;
using Unity.Mathematics;
public class Spawner : MonoBehaviour
{
[SerializeField] private Mesh mesh;
[SerializeField] private Material material;
void Start()
{
// エンティティの生成
EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
EntityArchetype archetype = entityManager.CreateArchetype(
typeof(Translation),
typeof(Rotation),
typeof(RenderMesh),
typeof(RenderBounds),
typeof(LocalToWorld));
Entity entity =entityManager.CreateEntity(archetype);
// Translationコンポーネントのデータの指定
entityManager.AddComponentData(entity, new Translation {
Value = new float3(2f, 0f, 4f)
});
// RenderMeshコンポーネントのデータの指定
entityManager.AddSharedComponentData(entity, new RenderMesh {
mesh = mesh,
material = material
});
}
}
AddComponentData() で、「Translation」コンポーネント(IComponentDataを継承)のデータを指定します。第1引数が「エンティティ」、第2引数が「コンポーネントデータ」になります。
AddSharedComponentData() で、「RenderMesh」コンポーネント(ISharedComponentDataを継承)のデータを指定します。
立方体を複数複製した場合、「Translation」はオブジェクト毎に別データですが、「RenderMesh」は同データで良いので、共有データコンポーネントになります。
(2) コンポーネント「Spawner」で、以下のように設定。
Mesh = Cube
Material = Default-Material
(3) 実行。
【おまけ】 エンティティの操作
◎ エンティティの生成
EntityArchetype archetype = entityManager.CreateArchetype(
typeof(Translation),
typeof(Rotation),
typeof(RenderMesh),
typeof(RenderBounds),
typeof(LocalToWorld));
entityManager.CreateEntity(archetype);
◎ エンティティのクローン
Entity entity = entityManager.Instantiate(entityPrefab);
◎ エンティティの破棄
entityManager.DestroyEntity(entity);
◎ コンポーネントの追加
・AddComponent(Entity, ComponentType) : すべて
・AddComponentData<T>(Entity, T) : 基本コンポーネント
・AddSharedComponentData<T>(Entity, T) : 共有コンポーネント
・AddBuffer<T>(Entity) : 動的バッファコンポーネント
・AddChunkComponentData<T>(Entity) : チャンクコンポーネント
・AddComponentObject(Entity, object) : コンポーネントオブジェクト
entityManager.AddComponentData(entity, new Translation {
Value = new float3(2f, 0f, 4f)
});
entityManager.AddSharedComponentData(entity, new RenderMesh {
mesh = mesh,
material = material
});
◎ コンポーネントの取得
・GetComponentData<T>(Entity) : 基本コンポーネント
・GetSharedComponentData<T>(Entity) : 共有コンポーネント
・GetBuffer<T>(Entity) : 動的バッファコンポーネント
・GetChunkComponentData<T>(ArchetypeChunk) : チャンクコンポーネント
・GetComponentObject<T>(Entity) : コンポーネントオブジェクト
Position position = entityManager.GetComponentData<Position>(entity);
◎ コンポーネントの更新
・SetComponentData<T>(Entity, T) : 基本コンポーネント
・SetSharedComponentData<T>(Entity, T) : 共有コンポーネント
・SetChunkComponentData<T>(ArchetypeChunk, T) : チャンクコンポーネント
entityManager.SetComponentData(entity, new Translation {
Value = new float3(2f, 0f, 4f)
});
動的バッファコンポーネントは、GetBuffer<T>でDynamicBuffer<T>構造体を取得し、それを使用して操作します。
DynamicBuffer<MyElement> buffer = EntityManager.GetBuffer<MyElement>(entity);
buffer.Add(new MyElement { Value = 123 });
buffer.RemoveAt(0);
◎ コンポーネントの削除
entityManager.RemoveComponent<Position>(entity);
【おまけ】 コンポーネントデータのコードの確認
◎ Transform
「Packages/Entities/Unity.Transforms/Translation」でコードを確認できます。
using System;
using Unity.Entities;
using Unity.Mathematics;
namespace Unity.Transforms
{
[Serializable]
[WriteGroup(typeof(LocalToWorld))]
[WriteGroup(typeof(LocalToParent))]
public struct Translation : IComponentData
{
public float3 Value;
}
}
◎ Rotation
「Packages/Entities/Unity.Transforms/Rotation」でコードを確認できます。
using System;
using Unity.Entities;
using Unity.Mathematics;
namespace Unity.Transforms
{
[Serializable]
[WriteGroup(typeof(LocalToWorld))]
[WriteGroup(typeof(LocalToParent))]
[WriteGroup(typeof(CompositeRotation))]
public struct Rotation : IComponentData
{
public quaternion Value;
}
}
◎ RenderMesh
「Packages/Hybrid Renderer/Unity.Rendering.Hybrid/RenderMeshProxy」でコードを確認できます。
using System;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
namespace Unity.Rendering
{
[Serializable]
[MaximumChunkCapacity(128)]
public struct RenderMesh : ISharedComponentData, IEquatable<RenderMesh>
{
public Mesh mesh;
public Material material;
public int subMesh;
[LayerField]
public int layer;
public ShadowCastingMode castShadows;
public bool receiveShadows;
public bool needMotionVectorPass;
public bool Equals(RenderMesh other)
{
return
mesh == other.mesh &&
material == other.material &&
subMesh == other.subMesh &&
layer == other.layer &&
castShadows == other.castShadows &&
receiveShadows == other.receiveShadows &&
needMotionVectorPass == other.needMotionVectorPass;
}
public override int GetHashCode()
{
int hash = 0;
if (!ReferenceEquals(mesh, null)) hash ^= mesh.GetHashCode();
if (!ReferenceEquals(material, null)) hash ^= material.GetHashCode();
hash ^= subMesh.GetHashCode();
hash ^= layer.GetHashCode();
hash ^= castShadows.GetHashCode();
hash ^= receiveShadows.GetHashCode();
hash ^= needMotionVectorPass.GetHashCode();
return hash;
}
}
[AddComponentMenu("DOTS/Deprecated/RenderMeshProxy-Deprecated")]
[Obsolete("RenderMeshProxy has been deprecated. Please use the new GameObject-to-entity conversion workflows instead. (RemovedAfter 2020-07-03).")]
public class RenderMeshProxy : SharedComponentDataProxy<RenderMesh>
{
internal override void UpdateComponentData(EntityManager manager, Entity entity)
{
if (!manager.HasComponent<LocalToWorld>(entity))
manager.AddComponentData(entity, new LocalToWorld {Value = float4x4.identity});
base.UpdateComponentData(manager, entity);
}
}
}
◎ RenderBounds
「Packages/Hybrid Renderer/Unity.Rendering.Hybrid/RenderBoundsComponent」でコードを確認できます。
using Unity.Entities;
using Unity.Mathematics;
namespace Unity.Rendering
{
public struct RenderBounds : IComponentData
{
public AABB Value;
}
public struct WorldRenderBounds : IComponentData
{
public AABB Value;
}
public struct ChunkWorldRenderBounds : IComponentData
{
public AABB Value;
}
}
◎ RenderBounds
「Packages/Entities/Unity.Transforms/LocalWorld」でコードを確認できます。
using System;
using Unity.Entities;
using Unity.Mathematics;
namespace Unity.Transforms
{
[Serializable]
[WriteGroup(typeof(WorldToLocal))]
public struct LocalToWorld : IComponentData
{
public float4x4 Value;
public float3 Right => new float3(Value.c0.x, Value.c0.y, Value.c0.z);
public float3 Up => new float3(Value.c1.x, Value.c1.y, Value.c1.z);
public float3 Forward => new float3(Value.c2.x, Value.c2.y, Value.c2.z);
public float3 Position => new float3(Value.c3.x, Value.c3.y, Value.c3.z);
public quaternion Rotation => new quaternion(Value);
}
}
この記事が気に入ったらサポートをしてみませんか?