Unity DOTS 1.0(6) Filter baking output机制和baking Prefab

本文介绍了UnityECS中的FilterBakingOutput机制,用于筛选在烘焙过程中不需要存储到磁盘的组件数据。同时,讨论了如何使用EntityPrefab、Prefab的管理以及在Baking过程中排除和实例化Prefab的方法,优化性能和资源消耗。
摘要由CSDN通过智能技术生成

Fliter baking output

概述:

  • 这是一种Baking机制,过滤掉那些不需要保存到entity scene的数据(磁盘上)。
  • 在实际的Baking的需求中,不是所有的都GameObject 需要转成entity,比如只在编辑器下使用的一些控制点。
  • Filter Baking Output, 就是把那些不需要转成的数据给他过滤掉,不输出出来。

操作方法:

  1. 排除Entity:

    • 如果你要把一个entity从Baking output里面排除:你可以在entity里面添加一个"BakingOnlyEntity" ecs Component 。这样在输出的时候那么这个entity就会被排除掉;
    • 当加了这样的一个组件到entity里面,unity就不会把这个enity保存到entity scene里面;也不会把它合并到ECS main world里面。
    • 两种方式:
      (1)在Baker里直接对entity添加BakingOnlyEntity组件,
      (2)在创作的时候直接对Authoring GameObjec上添加BakingOnlyEntityAuthoring组件
  2. 排除Component Data

    • 给这个组件加对应的注解Attributes就行
      • [BakingType]:那些被标记了BakingType的ComponentData都不会被输出到baking output , Bakeing结束时和Entiy同享的生命周期;

应用场景举例:

  • 我们每个entiy有一个bounding Box,随后又定义了一个Baking System,搜集所有的entity的bounding box,计算出来它们的convex hull(凸包).当这个Baking System结束以后,这个boundingBox这个数据就没有用了。所以这个bounding Box组件数据就不需要输出到output上,这个时候,你就可以使用[BakingType]或者[TemporaryBakingType]进行标注

示例代码:

[TemporaryBakingType]
        public struct TemporaryBakingData : IComponentData
        {
            public float Mass;
        }

        public struct SomeComputedData : IComponentData
        {
            // Computing this is too expensive to do in a Baker, we want to make use of Burst (or maybe Jobs)
            public float ComputedValue;
        }

        public class RigidBodyBaker : Baker<Rigidbody>
        {
            public override void Bake(Rigidbody authoring)
            {
                var entity = GetEntity(TransformUsageFlags.Dynamic);
                AddComponent(entity, new TemporaryBakingData{Mass = authoring.mass});

                // Even though we don't compute the data, we add the type from the Baker
                AddComponent(entity, new SomeComputedData());
            }
        }

        [WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
        [BurstCompile]
        partial struct SomeComputingBakingSystem : ISystem
        {
            // We are doing performance critical work here, so we use Burst
            [BurstCompile]
            public void OnUpdate(ref SystemState state)
            {
                // Because TemporaryBakingData is a [TemporaryBakingType] it only exists the same Bake pass that RigidBodyBaker ran
                // This means this Baking System will only run if the inputs to RigidBodyBaker change and cause it to re-bake
                // Additionally, because we are using no managed types in this system, we can use Burst
                foreach (var (computedComponent, bakingData) in
                         SystemAPI.Query<RefRW<SomeComputedData>, RefRO<TemporaryBakingData>>())
                {
                    var mass = bakingData.ValueRO.Mass;
                    float result = 0;
                    // Do heavy computation here, which is taking advantage of Burst
                    // result = ...
                    computedComponent.ValueRW.ComputedValue = result;
                }
            }
        }

Prefabs in baking

概述:

  • ECS 里面我们也可以把entity做成prefab,这样就可以非常方便的clone创建出来entity;
  • Entity prefab和GameObject prefab的使用方式都是类似的。
    • Step1:首先把GameObject Prefab Baking成Entity Prefab。
    • Step2:使用我们的entity Prefab来进行复制我们的entity。
  • Entity Prefab是一种特殊entity, 拥有以下两个Component
    • prefab tag: 区别了prefab entity与普通的entity,我们要查询世界所有entity的时候, 默认的查询规则就根据这个tag,排除掉prefab entity;
    • LinkedEntityGroup buffer: 一种保存所有孩子的entity的数据结构的引用.利用LinkedEntityGroup,可以非常方便的找到子entity
  • 使用注意:
    • entity prefab可以像GamePrefab一样在游戏运行的时候实例化entity出来
    • 在使用enity prefab之前必须要确保GameObject Prefab已经Bake转成了entity prefab,使它们在 entity scene可用。
    • 如果你得Authoring Scene有一个预制体关联得这个节点,那么Baking处理得时候,会把这个场景中预制体关联得节点当作普通节点,不会把它当作预制体去Bake。

将GameObject Prefab Baking成Entity Prefab方法

  • 为了确保预制体被烘焙并在实体场景中可用,必须将它们注册到一个baker中。这确保了对预制体对象的依赖性。当你在组件中引用实体预制体时,Unity会将内容序列化到使用它的subscene场景中。

Prefab in subscene 示例代码:

public struct EntityPrefabComponent : IComponentData
    {
    	//保存Entity Prefab用
        public Entity Value;
    }


    public class GetPrefabAuthoring : MonoBehaviour
    {
    	//关联用Prafab。通过Inspector面板挂载
        public GameObject Prefab;
    }

    public class GetPrefabBaker : Baker<GetPrefabAuthoring>
    {
        public override void Bake(GetPrefabAuthoring authoring)
        {
            // Register the Prefab in the Baker
            // 将Prefab直接转为Entity
            var entityPrefab = GetEntity(authoring.Prefab, TransformUsageFlags.Dynamic);
            // Add the Entity reference to a component for instantiation later
            // 获取当前entity 并将entityPrefab 赋予给Value值
            var entity = GetEntity(TransformUsageFlags.Dynamic);
            AddComponent(entity, new EntityPrefabComponent() {Value = entityPrefab});
        }
    }

PrefabReferenceInSubScene 示例代码:

  • 可以把当前的entity prefab序列化生成到一个单独的entity scene里面,这样多个subscene都可以重用这个(防止每个subscene单独加载)。
public struct EntityPrefabReferenceComponent : IComponentData
    {
    	//保存prefab引用
        public EntityPrefabReference Value;
    }

    public class GetPrefabReferenceAuthoring : MonoBehaviour
    {
        public GameObject Prefab;
    }

    public class GetPrefabReferenceBaker : Baker<GetPrefabReferenceAuthoring>
    {
        public override void Bake(GetPrefabReferenceAuthoring authoring)
        {
            // Create an EntityPrefabReference from a GameObject. This will allow the
            // serialization process to serialize the prefab in its own entity scene
            // file instead of duplicating the prefab ECS content everywhere it is used
            //通过EntityPrefabReference 获得entity prefab 引用
            var entityPrefab = new EntityPrefabReference(authoring.Prefab);
            var entity = GetEntity(TransformUsageFlags.Dynamic);
            AddComponent(entity, new EntityPrefabReferenceComponent() {Value = entityPrefab});
        }
    }

Instantiate Prefab 实例化预制

InstantiateEmbeddedPrefabs 代码实例(对应上面第一种Prefab使用方式):

public partial struct InstantiatePrefabSystem : ISystem
    {
        public void OnUpdate(ref SystemState state)
        {
            var ecb = new EntityCommandBuffer(Allocator.Temp);

            // Get all Entities that have the component with the Entity reference
            foreach (var prefab in
                     SystemAPI.Query<RefRO<EntityPrefabComponent>>())
            {
                // Instantiate the prefab Entity
                var instance = ecb.Instantiate(prefab.ValueRO.Value);
                // Note: the returned instance is only relevant when used in the ECB
                // as the entity is not created in the EntityManager until ECB.Playback
                ecb.AddComponent<ComponentA>(instance);
            }

            ecb.Playback(state.EntityManager);
            ecb.Dispose();
        }
    }

InstantiateLoadedPrefabs 代码实例(对应上面第二种Prefab使用方式):

  • 使用EntityPrefabReference时,必须先添加RequestEntityPrefabLoaded组件
  • unity会加载有RequestEntityPrefabLoaded的Entity Prefab,同时在加载完成时添加PrefabLoadResult组件
  • update的时候把加载好的entity prefab 找出来,然后调用Instantiate,实例化出来;
public partial struct InstantiatePrefabReferenceSystem : ISystem
    {
        public void OnStartRunning(ref SystemState state)
        {
            // Add the RequestEntityPrefabLoaded component to the Entities that have an
            // EntityPrefabReference but not yet have the PrefabLoadResult
            // (the PrefabLoadResult is added when the prefab is loaded)
            // Note: it might take a few frames for the prefab to be loaded
            var query = SystemAPI.QueryBuilder()
                .WithAll<EntityPrefabComponent>()
                .WithNone<PrefabLoadResult>().Build();
                //使用EntityPrefabReference时,必须先添加RequestEntityPrefabLoaded组件
            state.EntityManager.AddComponent<RequestEntityPrefabLoaded>(query);
        }

        public void OnUpdate(ref SystemState state)
        {
            var ecb = new EntityCommandBuffer(Allocator.Temp);

            // For the Entities that have a PrefabLoadResult component (Unity has loaded
            // the prefabs) get the loaded prefab from PrefabLoadResult and instantiate it
            foreach (var (prefab, entity) in
                     SystemAPI.Query<RefRO<PrefabLoadResult>>().WithEntityAccess())
            {
                var instance = ecb.Instantiate(prefab.ValueRO.PrefabRoot);

                // Remove both RequestEntityPrefabLoaded and PrefabLoadResult to prevent
                // the prefab being loaded and instantiated multiple times, respectively
                ecb.RemoveComponent<RequestEntityPrefabLoaded>(entity);
                ecb.RemoveComponent<PrefabLoadResult>(entity);
            }

            ecb.Playback(state.EntityManager);
            ecb.Dispose();
        }
    }

如何查询Prefab Entity

  • 默认情况下,Prefab是被排除在查询外,如果要包括进来,需要使用IncludePrefab 选项进行查询
public partial struct PrefabsInQueriesSystem : ISystem
    {
        public void OnUpdate(ref SystemState state)
        {
            #region PrefabsInQueries
            // This query will return all baked entities, including the prefab entities
            var prefabQuery = SystemAPI.QueryBuilder()
                .WithAll<BakedEntity>().WithOptions(EntityQueryOptions.IncludePrefab).Build();
            #endregion

            #region DestroyPrefabs
            var ecb = new EntityCommandBuffer(Allocator.Temp);

            foreach (var (component, entity) in
                     SystemAPI.Query<RefRO<RotationSpeed>>().WithEntityAccess())
            {
                if (component.ValueRO.RadiansPerSecond <= 0)
                {
                    ecb.DestroyEntity(entity);
                }
            }

            ecb.Playback(state.EntityManager);
            ecb.Dispose();
            #endregion
        }
    }
  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值