从Mono脚本生成Entity:深入理解Unity DOTS中的Archetype、Chunk与Entity结构设计

从Mono脚本生成Entity:深入理解Unity DOTS中的Archetype、Chunk与Entity结构设计

    正在检查是否收录...

从Mono脚本生成Entity:深入理解Unity DOTS中的Archetype、Chunk与Entity结构设计

Unity 的 DOTS(Data-Oriented Technology Stack)是面向性能极致优化的一种架构范式,其底层结构设计并非偶然,而是深思熟虑的结果。本篇文章将从开发者最熟悉的入口——MonoBehaviour 脚本 + Baker 入手,逐步剖析 DOTS 中 Entity 是如何生成与组织的,并深入理解其底层架构:Archetype、Chunk、Entity 的设计逻辑和动机。


一、从 MonoBehaviour + Baker 生成 Entity 说起

在 Unity DOTS 中,我们通过 Authoring + Baker 的方式将传统的 GameObject 转换为 Entity。一个常见的写法如下:

public class MonsterAuthoring : MonoBehaviour { public int MonsterType; class Baker : Baker<MonsterAuthoring> { public override void Bake(MonsterAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new Health { Value = 100 }); AddComponent(entity, new Translation { Value = float3.zero }); AddSharedComponent(entity, new MonsterType { TypeId = authoring.MonsterType }); } } }

表面上看,我们只是在添加组件。然而在背后,Unity DOTS 会根据这些组件自动为这个 Entity 创建归属结构——Archetype,并为其分配内存空间——Chunk。


二、Entity 是什么?

Entity 是 DOTS 中最基本的单位,但本身并不存储任何数据,它只是一个引用句柄:

public struct Entity { public int Index; // 在内部数组中的位置 public int Version; // 生命周期安全检测用 }

Entity 代表的是一个“ID”,它的数据存在 Chunk 中,它的组件定义了它的“能力和状态”。


三、Archetype:组件组合定义实体结构

当你给一个 Entity 添加了多个组件时,Unity 会自动根据这些组件的集合定义一个 Archetype。它可以理解为一个“结构签名”:

例如:

Archetype A = [Translation, Health, MonsterType] Archetype B = [Translation, Velocity]

所有具有相同组件组合的 Entity 都属于同一个 Archetype。这样做的好处是:

  • 可以快速定位拥有某些组件的所有实体

  • 方便数据批处理

  • 支持结构化存储(方便内存布局)


四、Chunk:结构化内存块

每个 Archetype 拥有若干个 Chunk。Chunk 是 DOTS 中用于存储实体数据的最小单位。

✅ Chunk 特点:

  • 大小固定为

    16KB

    (Unity 内部固定)

  • 所有 Entity 的组件数据按列式存储

  • 每个 Chunk 只容纳一种 Archetype 的实体

  • 同一个 Chunk 中所有 Entity 的 SharedComponent 值必须一致

🧮 一个 Chunk 容纳多少个 Entity?

取决于每个 Entity 拥有组件数据的总大小。

例如:

  • Entity 每个数据 32B,则 Chunk 容纳 16KB / 32 ≈ 512 个

  • 若数据变大(如包含 float4x4),Entity 变少


五、SharedComponent:控制 Chunk 分类的关键

SharedComponent 是一种特殊的组件,实现了 ISharedComponentData 接口。它的值不能在 Entity 级别存储,而是存储在 Chunk 的 header 区域。

特性:

  • 所有 Chunk 内的 Entity 必须拥有相同的 SharedComponent 值

  • 值不同的 Entity 不能放在同一个 Chunk 中

  • 更改 SharedComponent 值会导致 Entity 搬家(Chunk 移动)

使用场景:

  • 怪物类型分类(如 MonsterType)

  • LOD 分组、区域分组、渲染材质分组(RenderMeshArray)

注意:频繁更改 SharedComponent 会引起性能抖动


六、为什么 Chunk 是 16KB?

这个数字是深思熟虑后的硬件适配值:

  • L1 Cache 一般为 32KB,每个 Chunk 16KB 可以保证高缓存命中率

  • L2 Cache 较大,也能容纳多个 Chunk

  • 16KB 是内存对齐、批处理、页管理的黄金折中值

太小:Entity 太少、效率低 太大:Cache 溢出、处理慢

因此 Unity 默认设定为 16KB,不可修改。


七、Archetype、Chunk、Entity 的组织结构图(文字版)

Archetype A: [Translation, Health, MonsterType] │ ├─ Chunk A1 (MonsterType = 1) │ ├─ Entity 1 │ ├─ Entity 2 │ └─ ... │ ├─ Chunk A2 (MonsterType = 2) │ ├─ Entity 1001 │ └─ ... └─ ...

八、总结:设计背后的哲学

Unity DOTS 的 Archetype-Chuck-Entity 结构,融合了以下领域的精髓:

灵感来源应用点
数据导向设计 DoD 构建 Archetype 以优化访问结构
列式数据库 Chunk 内组件按列排列
稀疏集合(Index+Version) 安全地管理 Entity 生命周期
GPU 渲染管线 SharedComponent 控制分组渲染

其核心目标是:

利用现代硬件缓存特性,让大规模数据更新与处理高效而可控。


九、附:如何查看实际 Chunk/Archetype

  • 通过 Entities Hierarchy(Window → Entities)可视化工具查看 Chunk 分布

  • 通过代码:

EntityQuery query = GetEntityQuery(typeof(Health), typeof(MonsterType)); var chunks = query.ToArchetypeChunkArray(Allocator.Temp); Debug.Log($"Archetype has {chunks.Length} chunks");

结语

你只是在 Mono 脚本里写了几行 AddComponent,Unity 在背后已经帮你构建好了复杂而高效的数据处理架构。这就是 DOTS 的魅力所在——开发者专注逻辑,系统保障性能。

理解 Archetype、Chunk、Entity 的内在原理,是走向 DOTS 高效架构设计的第一步。

 

  • 本文作者:WAP站长网
  • 本文链接: https://wapzz.net/post-27007.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.8W+
9
1
2
WAP站长官方

微信视频号:开展直播团播低俗内容专项治理行动

上一篇

独家对话萨洛蒙:品牌的“高质量增长”是如何实现的

下一篇
评论区
内容为空

这一切,似未曾拥有

  • 复制图片
按住ctrl可打开默认菜单