最近DOTS终于发布了正式的版本, 我们来分享一下DOTS里面Baking阶段,Baking System,Baking World的关键概念,方便大家上手学习掌握Unity DOTS开发。Unity在Baking也是基于ECS模式开发设计的,所以Baking的时候也会有Baking System与Baking World,把Baking出来的数据放到Baking World里面。
Baking 的主要阶段
Baking有很多阶段,主要包含了两个关键的步骤:
-
Bakers: 在这个阶段所有 Baker 会被执行,就把authoring GameObject与Component 转换成ECS 的entities与components。
-
Baking System: 这个阶段,可以编写Baking System代码,统一批量对所有创建与生成好的Entities来做一些处理操作;
在Baker阶段执行之前,Unity会把subscene中所有的Authoring GameObject创建出对应的entity,这个阶段entity不包含任何组件数据,只包含一些metadata的描述数据。创建完Entity以后,就会执行Bakers 每个Baker处理对应它的authoring component的数据转化。每种类型的数据对应一种Baker,例如Entities Graphics就会有Baker将GameObject的渲染数据转换成renderers的数据。Unity Physics有Baker 把刚体RigidBody组件转成ecs数据。相同的类型只要一种Baker就即可。
Unity在运行Baker转换的时候,无法保证执行Baker的顺序, Baker不存在依赖关系。因此Baker不能去读取与改变entity中的组件数据,只能创建新的组件到entity。
当Baker阶段运行结束以后,所有的entity与组件就创建完成了,接下来就执行Baking System阶段。Baking System只会运行在Baking期间。你可以通过[UpdateAfter], [UpdateBefore] [UpdateInGroup]指定Baking System的运行时机。Unity有几个默认Baking System执行的时机分组。
-
PreBakingSystemGroup: 这个System分组执行发生在所有Bakers运行之前;
-
TransformBakingSystemGroup: 是一个用于处理实体的变换信息的系统组。它负责将实体的Transform数据进行烘焙,以提高性能和优化渲染。
-
BakingSystemGroup: 默认的Baking System都被放在了这个分组进行迭代处理;
-
PostBakingSytemGroup: 所有的放在默认分组中的Baking System全部迭代完成后,再来迭代这个分组里面的System;
实时Baking时,Unity会运行所有的baking system分组,它会把entity数据存入到entity scene,并序列化到磁盘。并把烘培出来后变化的数据同步到main ECS World里面。
Baking World
Unity 在Baker 每个entity scene的时候都是独立的。每次只处理一个场景。同时每个独立的场景都有一个独立的main world。同时在Baker每个场景的时候,我们的Unity会额外分配两个世界:
-
Conversion world: 定义了一个Baking发生的Word, 在Baking的时候,所有entity等数据都会被加入到这个World,在这个World里面做Baking。
-
Shadow world: 影子世界,存放的是上一次Baking完后的结果,方便与Conversion对比,来判断哪些在这次Baking时更新了。
Unity 会在 Conversion world 里面来运行Baker与Baking Sytems来做场景物体的Baking。当Baking结束以后,Unity Baking比较Shadow World与Conversion World的变化,看哪些改变了,Unity只把本次改变同步给main World。
Baking System
Baking System 是一种机制,被用于批量处理ecs components与entities的数据。一个Baking System在Unity DOTS内部也是一个System,它基于多线程与Burst 编译器,能够很好做批量的处理。Baking System与Baker机制不同的点在于Baker是将authoring data一个一个的处理转换,然后Baking System用户成批的处理已经转换好的ecs components与entities。所以Baking这个过程在执行Baking System 之前,必须要把要先执行让Baker把所有的entity 都初始化创建出来以后,才能只能执行Baking System, 批量处理。在Baking System中你可以改变当前World里面的所有内容,包括创建一个新的entities。这里要注意在Baking System里面创建一个entity,在bake 场景结束后不会被销毁。你可以在Baking System中创建一个entity,并传递给其它Baking System。如果你想要这个Entity在bake entity场景结束后销毁,你就必须要Baker里面来创建一个entity。当在Baking与实时Baking时,可以在Baker里面来调用CreateAdditionalEntity来创建entity,配合处理。
创建一个Baking System,我们需要给Baking System加上[WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]的注解。加了这个注解,我们系统Baker处理就会把它识别出来,并把它加入到Baking World里面来进行迭代。Unity每次Baking,都会迭代World里面的所有Baking System。接下来我们看一个Baking System 添加一个tag component到包含的某A组件的entity中的示例代码:
public struct AnotherTag : IComponentData { }
[WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
partial struct AddTagToRotationBakingSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
var queryMissingTag = SystemAPI.QueryBuilder()
.WithAll<RotationSpeed>()
.WithNone<AnotherTag>()
.Build();
state.EntityManager.AddComponent<AnotherTag>(queryMissingTag);
// Omitting the second part of this function would lead to inconsistent
// results during live baking. Added tags would remain on the entity even
// after removing the RotationSpeed component.
var queryCleanupTag = SystemAPI.QueryBuilder()
.WithAll<AnotherTag>()
.WithNone<RotationSpeed>()
.Build();
state.EntityManager.RemoveComponent<AnotherTag>(queryCleanupTag);
}
}
定义了一个Baking System, 每次迭代update的时候,找出World中所有包含RotationSpeed组件并且不含AnotherTag组件的Entity的集合,给它们加上AnotherTag组件,找出所有不包含RotationSpeed且包含AnotherTag的Entity集合,把它们的AnotherTag删除掉。
今天的Baking Phase, Baking World与Baking System就分享到这里了,关注我学习更多的最新Unity DOTS开发技巧。
尊敬的准VIP客户:
我们Unity DOTS课程也正式发布了,我们课程经过9年多的更新与迭代,已经涵盖了Unity 开发中遇到的绝大部分问题,涵盖了Unity主程序进阶,升职加薪所需要的系统的知识体系,主流游戏类型的重点难点技术解决方案。我们的老师10:00~23:00提供实时解答与回复,包含但不限于客户端+服务端。相信我们提供的游戏开发技术服务能很好的帮助到您。选择我们的VIP课程,您肯定不会后悔!有兴趣请 + 企.鹅.裙 428 540 563
下面是DOTS的VIP课程前18节视频,免费观看
Unity DOTS进阶与项目实战(B站18集)
第008课Baking系列之BakingSystem与BakingWorld详解
第009课FilterBakingOutput与PrefabsInBaking
第013课Managed与Unmanaged Component详解与性能分析