共享组件是一种特殊的数据组件,您可以使用它根据共享组件中的特定值(除了它们的原型之外)细分实体。当您向实体添加共享组件时,EntityManager 会将具有相同共享数据值的所有实体放入同一块中。
共享组件允许您的系统一起处理类似的实体。例如,作为Rendering.RenderMesh
Hybrid.rendering 包的一部分的共享组件定义了多个字段,包括mesh、material和receiveShadows。当您的应用程序呈现时,将这些字段的值相同的所有 3D 对象一起处理是最有效的。因为共享组件指定了这些属性,EntityManager 将匹配的实体放在内存中,以便渲染系统可以有效地迭代它们。
笔记
如果过度使用共享组件,可能会导致块利用率低下。这是因为当您使用共享组件时,它涉及基于原型和每个共享组件字段的每个唯一值的内存块数量的组合扩展。因此,避免将任何不需要将实体分类到共享组件的类别的字段添加到共享组件中。要查看块利用率,请使用Entity Debugger。
如果从实体中添加或删除组件,或更改共享组件的值,EntityManager 会将实体移动到不同的块,并在必要时创建新块。
您应该将IComponentData用于在实体之间变化的数据,例如存储世界位置、代理命中点或粒子生存时间。相反,当许多实体共享一些共同点时,您应该使用ISharedComponentData。例如在 DOTS 包中的 Boids 演示中,许多实体从同一个Prefab实例化,因此RenderMesh
许多Boid
实体之间是完全相同的。
[System.Serializable]
public struct RenderMesh : ISharedComponentData
{
public Mesh mesh;
public Material material;
public ShadowCastingMode castShadows;
public bool receiveShadows;
}
ISharedComponentData
每个实体的内存成本为零。您可以使用ISharedComponentData
将具有相同InstanceRenderer
数据的所有实体组合在一起,然后有效地提取所有矩阵进行渲染。生成的代码简单高效,因为数据在 ECS 访问时进行布局。
有关此示例,请参阅RenderMeshSystemV2
文件Packages/com.unity.entities/Unity.Rendering.Hybrid/RenderMeshSystemV2.cs
.
关于 SharedComponentData 的重要说明:
- ECS 将相同的实体分组
SharedComponentData
在相同的块中。它将索引存储到SharedComponentData
每个块一次,而不是每个实体。因此,SharedComponentData
每个实体的内存开销为零。 - 您可以使用EntityQuery迭代具有相同类型的所有实体。您还可以使用EntityQuery.SetFilter()专门遍历具有特定
SharedComponentData
值的实体。由于数据布局,此迭代的开销较低。 - 您可以使用
EntityManager.GetAllUniqueSharedComponents
检索SharedComponentData
添加到任何活动实体的所有唯一项。 - ECS 自动引用计数
SharedComponentData
。 SharedComponentData
应该很少改变。如果要更改 aSharedComponentData
,则需要使用memcpyComponentData
将该实体的所有内容复制到不同的块中。