Unity DOTS Baking System与Baking World
最近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删除掉。
原文地址:https://blog.csdn.net/voidinit/article/details/142514519
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!