Unity DOTS中的share component

Unity DOTS中的share component

share component是DOTS中一类比较特殊的component,顾名思义,它是全局共享的component,所有具有相同component值的entity,共享一个component,这就避免了数据的冗余。但是相应地,如果修改了某个entity上的share component值,则会触发structural change,Unity不得不将entity挪到使用新值的chunk中去。这就是说,对entity上share component值的修改,并非是真的修改了它的值,而是触发了entity的重新分组。在简要了解过它的利弊之后,我们来看一下Unity内部是如何管理share component的。

内存管理

Archetype不直接保存share component的值,而是保存了一个index数组,这些index用来真正索引share component值。虽然不同share component值的entity位于不同的chunk,但是这些chunk都属于同一个Archetype。一个Archetype可能包含多个share component的值,但每个chunk的share component值只有一个。

share component index在数组中的排序规则如上图所示,首先按不同的type进行排序,同一type再按chunk的index进行排序。share component index只保存设置过值的share component,意味着如果我们只是简单地调用AddComponent,而没有显式SetSharedComponent,压根就不会新增share component index。这是因为此时share component的值为默认值,并不需要显式保存。

share component真正的值保存在一个全局的m_UnmanagedSharedComponentsByType变量中。它可以认为是一个list数组,不同的component type对应不同的数组下标,share component index则映射到某个list的下标。当然,每个list的长度不一定相同。

在Unity Archetypes窗口中,可以看到share component是单独显示的:

创建流程

向Entity添加一个share component的流程和普通component类似,第一步也是去寻找满足相同type的Archetype,然后再去找是否有可复用的chunk存在。只不过这里判断chunk可复用的条件和普通component不同,普通component只需要满足chunk有空闲的slots即可,而share component还需要chunk所对应的share component value也要一致才行,如果找不到则会新建一个。

在有了chunk之后,就和普通component一样,需要把entity从之前的chunk中move到新的chunk中去。

c# 复制代码
public bool AddComponent(Entity entity, ComponentType type)
{
    var dstChunk = GetChunkWithEmptySlotsWithAddedComponent(entity, type);
    if (dstChunk == ChunkIndex.Null)
        return false;

    Move(entity, dstChunk);
    return true;
}

修改流程

当真正调用SetSharedComponent为share component设置值时,share component才会真正地存储下来。Unity内部为了在m_UnmanagedSharedComponentsByType中快速找到下一个空闲的位置,还使用了一个辅助数据结构m_UnmanagedSharedComponentInfo,它也是一个list数组,每个list的头部记录了list中下一个空闲的位置,所有空闲的位置以链表的形式串联在一起,如果不存在,则需要对list进行扩容。list中空闲的位置就是对应share component的index。

index更新之后,此时还需要把entity从原来index的chunk挪到新的index的chunk去,但Archetype不会改变,Archetype只和类型的数量有关,而每个chunk都有一个对应的share component index。

c# 复制代码
public void SetSharedComponentData_Unmanaged(
    Entity entity,
    TypeIndex typeIndex,
    void* componentData,
    void* componentDataDefaultValue,
    in SystemHandle originSystem = default)
{
    var componentType = ComponentType.FromTypeIndex(typeIndex);
    var newSharedComponentDataIndex = InsertSharedComponent_Unmanaged(typeIndex, 0, componentData, componentDataDefaultValue);
    EntityComponentStore->SetSharedComponentDataIndex(entity, componentType, newSharedComponentDataIndex);
}

销毁流程

remove share component的流程和普通component完全相同,此时的entity因为少了一个component,不再属于原来的Archetype,需要迁移到新的Archetype中去。如果此时的entity身上还有share component,那依旧按照之前寻找chunk的规则处理。

c# 复制代码
public bool RemoveComponent(Entity entity, ComponentType type)
{
    var dstChunk = GetChunkWithEmptySlotsWithRemovedComponent(entity, type);
    if (dstChunk == ChunkIndex.Null)
        return false;

    Move(entity, dstChunk);
    return true;
}

Reference

1\] [Introducing shared components](https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-shared-introducing.html)

相关推荐
lrh30252 小时前
Custom SRP - 16 Render Scale
3d·unity·srp·render pipeline·render scale
feiduoge5 小时前
教程 43 - 渲染目标和可配置渲染通道
windows·游戏引擎·图形渲染
ellis19709 小时前
Unity出安卓包知识点汇总
android·unity
DoomGT9 小时前
Audio - UE5中的音效播放重启问题
游戏·ue5·游戏引擎·虚幻·虚幻引擎
一线灵11 小时前
Axmol 开发环境快速搭建指南 (新)
游戏引擎
一线灵13 小时前
跨平台游戏引擎 Axmol-2.11.0 发布
游戏引擎
Robot侠13 小时前
ROS1从入门到精通 2:ROS1核心概念详解(节点、话题、服务一网打尽)
unity·游戏引擎·ros·机器人操作系统
世洋Blog1 天前
装饰器模式实践:告别臃肿的继承链,优雅解耦初始化状态管理
unity·设计模式·c#·装饰器模式
feiduoge1 天前
教程 41 - 增强纹理映射(采样器)
windows·游戏引擎·图形渲染
feiduoge1 天前
教程 37 - 法线贴图
windows·游戏引擎·图形渲染