Unity DOTS中的baking(三)过滤baking的输出

Unity DOTS中的baking(三)过滤baking的输出

默认情况下,在conversation world(baker和baking system运行的环境)下产生的所有entities和components,都会作为baking环节的输出。在baking结束时,Unity必须将自上次baking以来发生变化的任何数据,都要复制到main world。不过,有些数据其实只在编辑时有用,我们希望可以在baking输出的时候将其舍弃掉。为此,Unity也提供了一些过滤的手段进行支持。

首先是属性BakingType,它用来标记一个component,使其只会存在于conversation world,不会输出到main world中。我们来看一个例子:

public class MyAuthoring : MonoBehaviour
{public int bakeIntData = 0;public ImageGeneratorInfo info;class MyBaker : Baker<MyAuthoring>{public override void Bake(MyAuthoring authoring){Debug.Log("==========================Bake Invoked!========================== " + authoring.name);DependsOn(authoring.info);if(authoring.info == null) return;//var transform = authoring.transform;var transform = GetComponent<Transform>();var entity = GetEntity(TransformUsageFlags.None);AddComponent(entity, new MyComponent {value = authoring.bakeIntData,spacing = authoring.info.Spacing,position = transform.position});AddComponent(entity, new MyComponentBakingType {value = authoring.bakeIntData});}}
}public struct MyComponent : IComponentData
{public int value;public float spacing;public float3 position;
}[BakingType]
public struct MyComponentBakingType : IComponentData
{public int value;
}

这个例子中,我们在Baker里为entity添加了两个component,其中MyComponentBakingType是一个标记了BakingType属性的component。那么,在conversation world下,可以看到这两个component都存在于entity上:

Unity DOTS中的baking(三)1

而在editor world下,就只剩下MyComponent这一个component了:

Unity DOTS中的baking(三)2

接下来我们来研究研究Unity在其背后做了哪些事情。首先对于BakingType属性,Unity在TypeManager中定义了一个与之匹配的常量:

/// <summary>
/// Bitflag set for component types decorated with the <seealso cref="BakingTypeAttribute"/> attribute.
/// </summary>
public const int BakingOnlyTypeFlag = 1 << 20;

然后在add component时,会对component所定义的属性进行判断:

bool isBakingOnlyType = Attribute.IsDefined(type, typeof(BakingTypeAttribute));
if (isBakingOnlyType)typeIndex |= BakingOnlyTypeFlag;

TypeManager还对外暴露了IsBakingOnlyType这一get属性:

public bool IsBakingOnlyType 
{[MethodImpl(MethodImplOptions.AggressiveInlining)] get { return  (Value & TypeManager.BakingOnlyTypeFlag) != 0; } 
}

这一get属性会在GatherComponentChangesBuildPackedGatherComponentChangesJob两个job中使用,它们用来收集发生变化的components,但包含BakingType属性的component会被过滤掉。这两个job由EntityManagerDiffer类触发:

/// <summary>
/// Generates a detailed change set for the world.
/// All entities to be considered for diffing must have the <see cref="EntityGuid"/> component with a unique value.
/// </summary>
/// <remarks>
/// The resulting <see cref="EntityChanges"/> must be disposed when no longer needed.
/// </remarks>
/// <param name="options">A set of options which can be toggled.</param>
/// <param name="allocator">The allocator to use for the results object.</param>
/// <returns>A set of changes for the world since the last fast-forward.</returns>
public EntityChanges GetChanges(EntityManagerDifferOptions options, AllocatorManager.AllocatorHandle allocator)
{var changes = EntityDiffer.GetChanges(ref m_CachedComponentChanges,srcEntityManager: m_SourceEntityManager,dstEntityManager: m_ShadowEntityManager,options,m_EntityQueryDesc,m_BlobAssetCache,allocator);return changes;
}

从代码中可以猜测出,这里的变化指的是conversation world和shadow world之间的diff,conversation world就是baker和baking system运行的地方,而shadow world则是上一次baking环节输出的拷贝,Unity使用这个shadow world,与当前baking的输出进行对比,只把不同的components和entities拷贝到main world,然后再更新shadow world为当前的conversation world。那么,既然代码中调用的两个job会把包含BakingType属性的component过滤掉,很明显最后输出到main world的components就不包含它们了。

除了BakingType属性之外,Unity还提供了TemporaryBakingType属性标记一个component。这两者有什么区别呢?Unity官方文档中给出了一段说明:

You can also exclude components with the following attributes:

  • [BakingType]: Filters any components marked with this attribute from the baking output.
  • [TemporaryBakingType]: Destroys any components marked with this attribute from the baking output. This means that components marked with this attribute don’t remain from one baking pass to the next, and only exist during the time that a particular baker ran.

可以得知,TemporaryBakingType属于那种阅后即焚的操作,拥有该属性的component,会在触发相应的baking时add到entity上,然后在baking结束时component就会被销毁,这意味着该component也不会一直存在于conversation world。之后,如果不再触发相应的baking,那么该component在conversation world里也不复存在。

这么说有点枯燥,我们还是用代码进行实验,在前面例子的基础上,新增定义一个component,然后在authoring Bake函数中add一下:

[TemporaryBakingType]
public struct MyComponentTempBakingType : IComponentData
{public int value;
}public override void Bake(MyAuthoring authoring)
{AddComponent(entity, new MyComponentTempBakingType{value = authoring.bakeIntData});
}

由于它在conversation world中也是转瞬即逝,我们没法直接在编辑器观察到它。这里需要借助一下BakingSystem,BakingSystem是一类只存在baking过程中的system,它负责把各种baker产生的输出做进一步处理,而我们这里就是要观察baker中TemporaryBakingType属性的component。

[WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
[BurstCompile]
public partial struct MyAuthoringBakingSystem : ISystem
{EntityQuery m_query;[BurstCompile]public void OnCreate(ref SystemState state){m_query = SystemAPI.QueryBuilder().WithAll<MyComponentTempBakingType>().Build();state.RequireForUpdate(m_query);}[BurstCompile]public void OnUpdate(ref SystemState state){Debug.Log("=================update my authoring baking system===================");}
}

OnCreate会在system创建的时候执行一次,代码中就是获取当前包含MyComponentTempBakingTypecomponent的entity,如果存在这样的entity,则system才会执行OnUpdate。那么,根据我们之前的假设,这里的OnUpdate只会执行一次。实际上也是如此:

Unity DOTS中的baking(三)3

类似地,暗地里Unity在TypeManager中定义了一个flag常量:

/// <summary>
/// Bitflag set for component types decorated with the <seealso cref="TemporaryBakingTypeAttribute"/> attribute.
/// </summary>
public const int TemporaryBakingTypeFlag = 1 << 21;

然后对外暴露名为TemporaryBakingType的get属性:

/// <summary>
/// <seealso cref="TypeIndex.IsTemporaryBakingType"/>
/// </summary>
public bool TemporaryBakingType => IsTemporaryBakingType(TypeIndex);

最终这一属性会被Unity内部的BakingStripSystem所使用,在OnCreate时会创建所有带有该attribute的entity query:

protected override void OnCreate()
{var allTypes = TypeManager.AllTypes.Where(t => t.TemporaryBakingType).ToArray();m_BakingComponentQueries = new NativeArray<(ComponentType, EntityQuery)>(allTypes.Length, Allocator.Persistent);for(int i = 0; i < allTypes.Length; i++){var componentType = ComponentType.FromTypeIndex(allTypes[i].TypeIndex);EntityQueryDesc desc = new EntityQueryDesc(){All = new ComponentType[] {componentType},Options = EntityQueryOptions.IncludeDisabledEntities | EntityQueryOptions.IncludePrefab};m_BakingComponentQueries[i] = (componentType, GetEntityQuery(desc));}
}

然后每次update时,对符合条件的entity移除掉带有MyComponentTempBakingType属性的component:

protected override void OnUpdate()
{using (s_stripping.Auto()){foreach(var (componentType, query) in m_BakingComponentQueries){EntityManager.RemoveComponent(query, componentType);}}
}

BakingTypeMyComponentTempBakingType都是用来过滤component的,Unity还提供了一种过滤entity的方式,即给需要过滤掉的entity上添加一个名为BakingOnlyEntity的component。

AddComponent<BakingOnlyEntity>(entity);

这样这个entity就只会存在于conversation world中:

Unity DOTS中的baking(三)4

Unity DOTS中的baking(三)5

背后的实现也很简单,就是有一个专门处理这个component的system,筛选出符合条件的entity,把它们一一销毁掉:

protected override void OnCreate()
{_DestroyRemoveEntityInBake = new EntityQueryBuilder(Allocator.Temp).WithAny<RemoveUnusedEntityInBake, BakingOnlyEntity>().WithOptions(EntityQueryOptions.IncludeDisabledEntities | EntityQueryOptions.IncludePrefab).Build(this);
}protected override void OnUpdate()
{EntityManager.DestroyEntity(_DestroyRemoveEntityInBake);
}

Reference

[1] Filter baking output

[2] Baking worlds overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/665997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android学习之路(29) Gradle初探

前言: 大家回想一下自己第一次接触Gradle是什么时候&#xff1f; 相信大家也都是和我一样&#xff0c;在我们打开第一个AS项目的时候&#xff0c; 发现有很多带gradle字样的文件&#xff1a;setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各种配置&#xff…

将给定的二维数组旋转90度numpy.rot90()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将给定的二维数组旋转90度 numpy.rot90() [太阳]选择题 以下说法中正确的是? import numpy as np a np.array([[1,1,1],[2,2,2],[3,3,3]]) print("【显示】a:\n",a) print("…

MIT 6.5830 概述

简介 同MIT6.824系列类似&#xff0c;6.4830是关于Database System的一门课程&#xff0c;官方主页链接。 从课程信息可知&#xff0c;理论课分为 21 个课时&#xff0c;3个问题集&#xff0c;4个实验&#xff0c;1个项目。课程的 ppt 可以下载&#xff0c;对应的课堂回放可以…

H5 加密(MD5 Base64 sha1)

1. 说明 很多的时候是避免不了注册登录这一关的&#xff0c;但是一般的注册是没有任何的难度的&#xff0c;无非就是一些简单的获取用户输入的数据&#xff0c;然后进行简单的校验以后调用接口&#xff0c;将数据发送到后端&#xff0c;完成一个简单的注册的流程&#xff0c;那…

零基础Vue框架上手;git,node,yarn安装

项目搭建环境&#xff1a; git安装&#xff1a;Git - 安装 Git (git-scm.com)&#xff08;官网&#xff09; 下载路径&#xff1a;Git - Downloading Package (git-scm.com)&#xff1b;根据自己电脑下载相对应的安装包 ​ 点next ​ 点next&#xff0c;点到最后安装就行。…

新 CentOS 7 服务器的基本配置

简介 在为新服务器设置最低配置之后&#xff0c;大多数情况下都建议进行一些额外的步骤。在本指南中&#xff0c;我们将继续配置我们的服务器&#xff0c;处理一些推荐但可选的程序。 先决条件和目标 在开始本指南之前&#xff0c;您应该先运行 CentOS 7 初始服务器设置指南…

8-CentOS7.9安装Docker时报“Requires: container-selinux >= 2:2.74”等错误

1.问题描述 CentOS7.9服务器安装Docker时,报“Requires: container-selinux >= 2:2.74”错误,具体如下: [root@logstash ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [root@logstash yum.repos.d]# yum install docker-ce Loaded plugins: fas…

开关电源学习之Buck电路

一、引言 观察上方的电路&#xff0c;当开关闭合到A点时&#xff0c;电流流过电感线圈&#xff0c;形成阻碍电流流过的磁场&#xff0c;即产生相反的电动势&#xff1b;电感L被充磁&#xff0c;流经电感的电流线性增加&#xff0c;在电感未饱和前&#xff0c;电流线性增加&…

信号传输中出现的畸变与解决方法

当数字电路的输出由低电平向高电平瞬变时,与电路输出 端相连的传输线的对地电容要被充电到与电路输出高电平 相等才为止;而当电路的输出由高电平向低电平瞬变时,传输线的分布电容要通过电路输出端来进行放电。由于电路的输出阻抗较低,分布电容放电的瞬态电流较大,这个电流…

docker compose部署一个windows

前置准备 centos centos开启kvm centos内存:16G 安装 docker安装 docker run -it \ -e VERSION"win11" \ -e RAM_SIZE"8G" \ -e CPU_CORES"4" \ -e DISK_SIZE"256G" \ -e MANUAL"N" \ -p 8006:8006 \ -p 3389:3389/tcp …

前端vue/react项目压缩图片工具@yireen/squoosh-browser

想要在前端项目中压缩图片&#xff0c;然后再上传到后端保存&#xff0c;就需要一个压缩工具的帮助&#xff0c;暂时有两个依赖库可以选择&#xff1a;image-conversion和yireen/squoosh-browser&#xff0c;看了官方仓库地址和更新时间等详情&#xff0c;发现还是yireen/squoo…

Apache POl Excel

目录 介绍 Apache POl的应用场景&#xff1a; 入门使用 通过POI创建Excel文件并且写入文件内容 通过POI读取Excel文件中的内容 介绍 Apache POl是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用POI在Java程序中对Miscrosoft O…

项目中将sass更换成less(TypeError: this.getOptions is not a function已解决)

在更换之前&#xff0c;首先了解sass与less在用法上的区别有哪些&#xff08;这里简单提几个&#xff09;&#xff1a; 变量区别&#xff1a;Less中用&#xff0c;Sass用$sass支持条件语句&#xff0c;可以使用if{}else{}、for循环等&#xff0c;而less不支持在定义变量时候&a…

迅为RK3588开发板windows与开发板互传使用U盘进行拷贝

1 将 U 盘(U 盘的格式必须为 FAT32 格式&#xff0c;大小在 32G 以下)插到开发板的 usb 接口&#xff0c;串口打印信息如下所示&#xff0c;U 盘的设备节点是/dev/sdb4。U 盘的设备节点不是固定的&#xff0c;根据实际情况来查看设备节点。 2 输入以下命令挂载 U 盘&#xff0c…

Unity游戏开发架构设计指南

前言 在Unity游戏开发中&#xff0c;合理的架构设计对于确保项目的可维护性和可扩展性至关重要。一个良好的架构能够帮助开发者更有效地组织代码&#xff0c;便于团队协作&#xff0c;同时也能够应对项目需求的变化。 初步理解游戏架构 游戏架构是指在游戏开发过程中&#xff0…

【揭秘】JMeter JDBC脚本实战,让你的性能测试更高效!

Jmeter使用jdbc的场景&#xff1a; 1、接口功能测试时&#xff0c;需要查询验证码 2、通过数据库查询已经注册的手机号码 3、性能测试时&#xff0c;直接对某个SQL做性能测试&#xff0c;快速的发现性能问题 添加一个jdbc的配置元件 配置jdbc连接信息 配置说明&#xff1a; 1…

【24.2.3笔记】C++ Primer 自学Day 20

四、表达式 12、bitset 操作 操作功能用法test(pos)pos位是否为1&#xff1f;a.test(4)any()任意位是否为1&#xff1f;a.any()none()是否没有位为1&#xff1f;a.none()count()值是1的位的个数a.count()size()位元素的个数a.size()[pos]访问pos位a[4]flip()翻转所有的位a.fl…

基于 Python 的 Web 应用程序的 Web 服务器比较

简介 在本文中&#xff0c;我们将讨论三个主要内容&#xff1a;Python、Web 服务器&#xff0c;以及两者之间最重要的细节。 开玩笑的话&#xff0c;这篇相当长的文章对于一些寻求快速指导或答案的人来说可能看起来有些严肃。不幸的是&#xff0c;与 Python 世界中的大多数事物…

153基于matlab的滚动轴承故障诊断

基于matlab的滚动轴承故障诊断&#xff0c;基于小波包分解&#xff0c;得到数据峭度值&#xff0c;以正常与故障数据峭度差值进行最大尺度重构&#xff0c;对重构信号进行包络谱分析。程序已调通&#xff0c;可直接运行。 153matlab 信号重构 包络谱分析 故障诊断 (xiaohongshu…

工业物联网接入网关在制造企业的实际应用-天拓四方

随着工业4.0和智能制造的兴起&#xff0c;工业物联网&#xff08;IIoT&#xff09;已成为工厂自动化的关键驱动力。在这个转变中&#xff0c;工业物联网网关扮演着至关重要的角色。它们充当了设备与企业系统之间的桥梁&#xff0c;实现了数据采集、分析和设备控制等功能。 案例…