Unity构建详解(3)——SBP的依赖计算

【前置知识】

先要搞清楚Asset和Object的关系,可以简单理解为一个Asset对应多个Object。

unity自定义的Asset也要有一个存储的标准,其采用的是YAML,我们看到的所有Unity自定义的Asset格式,例如.prefab(预制体),.scene(场景文件),.asset(资源文件,例如ScriptableObject),.mat(材质球),.controller(动画状态机),还有图集等。

例如,prefab文件用YAML的格式记录了该Asset包含的Object,每个Object有一个FileID,用于区分Asset内的Object,每个Object中会记录自身的属性信息、包含的Type、引用的其他Object、引用的其他Asset、引用的其他Asset的Object等信息。

ObjectIdentifier是YAML中的Object的简要记录

可以建立这样一个层级一对多关系:Asset->Object->Type

【Native接口】

  • 获取一个Asset引用的其他Asset
    •  AssetDatabase.GetDependencies,可以获取直接或间接依赖, 这个操作比较耗时,可以优化Unity中资源依赖关系获取效率优化 - 知乎
  • 获取一个Asset引用的其他Asset的Hash值
    •  AssetDatabase.GetAssetDependencyHash
  • 获取一个Asset包含的ObjectIdentifier
    •  ContentBuildInterface.GetPlayerObjectIdentifiersInAsset
  • 获取一个或一系列Object引用的其他Object
    •  ContentBuildInterface.GetPlayerDependenciesForObjects
  • 获取一个Object中包含的Type
    •  ContentBuildInterface.GetTypesForObject
  • 获取一个Asset在目标平台上的Object,例如有些Object只在Editor上用,打包时要剔除
    •  ContentBuildInterface.GetPlayerAssetRepresentations
  • 计算Asset的使用情况,例如是否使用光照、雾效、阴影等,结果放在BuildUsageTagSet中
    •  ContentBuildInterface.CalculateBuildUsageTags

【什么是增量构建】

增量是缓存的一种方式,每次在已有缓存的基础上进行构建,就是增量构建。一般的缓存,例如对象池等,其数据还在内存中,增量时缓存数据要保存在磁盘中,构建时再加载到内存中。

【如何读代码】

我们看到的代码是完整的增量构建代码,但我们读代码时要分开来读。

构建是基础的,增量是新加的。要先看如何构建的,再看如何做增量的。

看构建时,要看:输入数据从哪来、输入数据如何使用(即输出数据从哪来)、输出数据是什么

看增量时,要看:缓存数据从哪来如何保存、缓存数据如何读取、缓存数据如何使用

总之要分开多个步骤跳着看,不要从方法的第一行顺着看到最后一行,很容易晕,而且也看不懂。

【CalculateSceneDependencyData】

输入数据从哪来

要计算场景的依赖,我们可以配置决定要计算哪些场景,配置好后会被保存到m_Content.Scenes 

 输入数据如何使用

这里就是如何计算得到场景的依赖数据,核心是调用

ContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache);

返回值是SceneDependencyInfo结构体,其包含四个字段:

  • internal string m_Scene; 场景的名字
  • internal ObjectIdentifier[] m_ReferencedObjects;依赖的物体
  • internal Type[] m_IncludedTypes;包含的类型
  • internal BuildUsageTagGlobal m_GlobalUsage; 使用的类型

依赖分为递归和非递归两种,递归就是要依次获取所有的依赖,非递归只要获取直接依赖。

输出数据是什么
  • 得到所有Scene的依赖数据,放入到BuildDependencyData中,其是该Task的输出Data
    • m_DependencyData.SceneInfo.Add(asset, sceneInfo);
缓存数据如何获取

同一个对象,在不同的系统中会有不同的表示,也即会有不同的类,类中会有些相同的字段来表示同一个对象。

在构建中,场景的依赖数据放在SceneDependencyInfo中,每个Object对应一个 ObjectIdentifier

在增量中,场景的缓存数据放在CachedInfo中,每个Asset对应一个CacheEntry

缓存数据获取代码在if (uncachedInfo != null)中:

  • 通过AssetDatabase.GetDependencies获取某个场景依赖的Asset
  • 得到依赖中类型为prefab的CacheEntry
  • 计算所有CacheEntry的hash128,通过其了解场景的依赖是否发生变化
  • 计算得到该场景对应的CachedInfo
  • 保存所有场景的CachedInfo
缓存数据如何保存

保存代码为:m_Cache.SaveCachedData(uncachedInfo)

实现在 BuildCache.SaveCachedData中,用多线程进行保存的,用多线程是为了加速。

这里需要保存成文件,要有输入路径,也是可以配置的,默认是"Library/BuildCache"

缓存数据如何读取

读取代码为:m_Cache.LoadCachedData(entries, out cachedInfo);

要看懂数据如何读取/导入,要先看数据如何保存/导出

缓存数据如何使用

缓存数据必然包含输出数据,一般而言,就是直接拿来用,复杂些需要做个转换。这里直接拿来用即可。

使用缓存数据的核心问题是缓存的数据是不是最新的,有效的。因此,在使用缓存数据前,必须要有个方式判断缓存数据是否有效。

这里的方式是如果引用的Object的类型是Sprite,那么重新计算场景的依赖,得到新的ObjectIdentifier,对比前后的ObjectIdentifier以判断缓存数据是否有效。

【增量的数据结构】

CacheEntry:
  • public GUID Guid //该资源的GUID
  • public int Version //该资源的版本号,一般是1
  • public EntryType Type //该资源的类型,分为Asset\Data\File\ScriptType 四种,一般为Asset
  • public Hash128 Hash 
  • internal InclusionType Inclusion //显式还是隐式包含,明确配置的要收集的Asset是显式的,没有被配置但被配置的引用的Asset是隐式的
  • public string File //文件类型时文件的名字
  • public string ScriptType //脚本类型时脚本的名字
CachedInfo
  • public CacheEntry Asset 自身的CacheEntry
  • public CacheEntry[] Dependencies依赖的对应的CacheEntry
  • public object[] Data其他附加信息,这里用个Object[]数组来统合不同情况的数据,类似一个object类型的参数,很常见的处理方式。场景的Data为:
    • SceneDependencyInfo
    • BuildUsageTagSet
    • prefabDependency的Hash128
    • List<ObjectTypes> 每个Object所涉及的Type,即哪些脚本类

【CalculateAssetDependencyData】

构建时

将输入和输出数据又做了一层封装,封装成TaskInput和TaskOutput,感觉没有必要。

  • 输入数据就是要收集的所有Asset:m_Content.Assets
  • 计算该Asset的依赖数据
    •  var includedObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset
    • var referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects
  • 计算Object的依赖的Object数据
  • 计算对象构建使用情况
    • ContentBuildInterface.CalculateBuildUsageTags
  • 对于Sprite类型的资源,生成SpriteImporterData
  • 获取Asset的AssetRepresentations放入ExtendedAssetData,剔除Editor上的Object
    •  ContentBuildInterface.GetPlayerAssetRepresentations
  • 得到输出数据
    • 所有Asset的依赖数据,放入到BuildDependencyData中
      •  m_DependencyData.AssetInfo.Add(o.asset, o.assetInfo);
    • 所有Object的依赖数据,放入ObjectDependencyData中
      •  m_ObjectDependencyData.ObjectDependencyMap[objectDependencyInfo.Object] = objectDependencyInfo.Dependencies;
    • 所有Sprite的数据,放入BuildSpriteData中
      • m_SpriteData.ImporterData.Add(o.asset, o.spriteData)
    • 所有平台相关的数据,放入BuildExtendedAssetData中
      • m_ExtendedAssetData.ExtendedData.Add(o.asset, o.extendedData);
    • 所有的使用情况数据,放入BuildDependencyData中
      •   m_DependencyData.AssetUsage.Add(assetOutput.asset, assetOutput.usageTags);
增量时
  • 获取缓存数据GetCachedInfo,同样是CacheInfo这个数据结构
    •  public CacheEntry Asset //自身的CacheEntry
    • public CacheEntry[] Dependencies //依赖的Asset的CacheEntry,可以通过依赖的ObjectObjectIdentifier的GUID找到依赖的Asset
    • 自定义的数据,有些冗余
      •  BuildUsageTagSet
      • SpriteImporterData
      • ExtendedAssetData
      • List<ObjectTypes>
      • List<ObjectDependencyInfo>
      • AssetLoadInfo 类同SceneDependencyInfo
        •  internal GUID m_Asset; 自身的GUID
        • internal string m_Address 自身的路径
        • internal List<ObjectIdentifier> m_IncludedObjects; 包含的Object
        • internal List<ObjectIdentifier> m_ReferencedObjects; 引用的所有Object
  • 缓存数据的保存、读取和使用类同场景

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

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

相关文章

研华工控机610L学习笔记2:visualstudio与第一个C#程序

今日继续学习工控机 C# 编程相关知识&#xff1a; 这篇结束后我将先进行一段时间的C#的学习研究&#xff0c;并写一些C#的笔记 后续再更新工控机编程设计相关 目录 1、安装visualstudio&#xff1a; 2、创建第一个C#程序&#xff1a; 3、寻找C#解决方案源文件&#xff1a; …

linux之zabbix自定义监控

zabbix基本配置见&#xff1a;写文章-CSDN创作中心https://mp.csdn.net/mp_blog/creation/editor/136783672 自定义监控规则 命令为who | wc -l 显示为2&#xff0c;主机一个&#xff0c;mobaxterm一个&#xff0c;思路是开启3个终端&#xff0c;让主机的zabbix服务自动检测1…

B端设计:如何让UI组件库成为助力,而不是阻力。

首发2023-09-24 15:42贝格前端工场 Hi&#xff0c;我是大千UI工场&#xff0c;网上的UI组件库琳琅满目&#xff0c;比如elementUI、antdesign、iview等等&#xff0c;甚至很多前端框架&#xff0c;也出了很多UI组件&#xff0c;如若依、Layui、bootstrap等等&#xff0c;作为U…

I/O多路复用:select/poll/epoll

最基本的 Socket 模型 要想客户端和服务器能在网络中通信&#xff0c;那必须得使用 Socket 编程&#xff0c;它是进程间通信里比较特别的方式&#xff0c;特别之处在于它是可以跨主机间通信。 Socket 的中文名叫作插口&#xff0c;咋一看还挺迷惑的。事实上&#xff0c;双方要…

基于SpringBoot图书进销存管理系统

采用技术 基于SpringBoot图书进销存管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 用户信息管理 图书类型管理 商品退货管理 客户信息管理 图…

软件测试相关内容第六弹 -- 测试实战

写在前&#xff1a;hello大家早中晚上好&#xff01;这里是西西&#xff0c;前面我们已经学习了关于测试相关基础的介绍&#xff0c;点击链接直达前方内容~ 测试内容博客链接初识软件测试点击跳转软件测试相关概念点击跳转测试生命周期、BUG、测试大体流程点击跳转测试用例、测…

数据结构·排序

1. 排序的概念及运用 1.1 排序的概念 排序&#xff1a;排序是将一组“无序”的记录序列&#xff0c;按照某个或某些关键字的大小&#xff0c;递增或递减归零调整为“有序”的记录序列的操作 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同关键字的记…

day03_mysql_课后练习 - 参考答案

文章目录 day03_mysql_课后练习mysql练习题第1题第2题第3题第4题第5题 day03_mysql_课后练习 mysql练习题 第1题 案例&#xff1a; 1、创建一个数据库&#xff1a;day03_test01_school 2、创建如下表格 表1 Department表的定义 字段名字段描述数据类型主键外键非空唯一D…

Docker 笔记(七)--打包软件生成镜像

目录 1. 背景2. 参考3. 文档3.1 使用docker container commit命令构建镜像3.1.1 [Docker官方文档-docker container commit](https://docs.docker.com/reference/cli/docker/container/commit/)Description&#xff08;概述&#xff09;Options&#xff08;选项&#xff09;Exa…

【Redis】Redis特性

Redis 认识redisRedis特性在内存中存储数据可编程可扩展性持久化Clustering高可用性 认识redis Redis&#xff0c;英文全称是Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志…

【JAVA】封装与包

。何为封装呢&#xff1f;简单来说 就是套壳屏蔽细节 封装&#xff1a;将数据和操作数据的方法进行有机结合&#xff0c;隐藏对象的属性和实现细节&#xff0c;仅对外公开接口来和对象进行 交互 访问限定符 public&#xff1a;可以理解为一个人的外貌特征&#xff0c;谁都可以…

【webpack】----错误解决【Cannot read properties of undefined (reading ‘tap‘)】

1. 报错场景 安装 webpack-obfuscator 后&#xff0c;进行 js 代码混淆编译的时候报错。 2. 报错截图 3. 错误原因 通常是由于版本不兼容或配置错误引起的。 4. 查询本地 webpack 版本 4.1 查询命令 npm 查询 npm view webpack versionyarn 查询 yarn info webpack ver…

Java学习笔记 | JavaSE基础语法 | 04 | 数组

文章目录 0.前言1.数组2.数组声明2.1 数组定义2.2 数组初始化1.静态初始化2.动态初始化3.区别4.数组的默认初始化值&#xff1a; 2.3 数组名 3.访问数组3.1 索引3.2 访问数组3.3 length属性 4.数组常见问题5.数组内存分析5.1 内存分配5.2 数组内存分配 6.数组的练习练习1&#…

吴恩达深度学习笔记:神经网络的编程基础2.1-2.4

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第二周&#xff1a;神经网络的编程基础 (Basics of Neural Network programming)2.1 二分类(Binary Classification)2.2 逻辑回归(Logistic Regression)2.3 逻辑回归的代价函数&#xff08;Lo…

MySQL:数据类型

文章目录 数据类型分类数值类型越界访问bit类型小数类型floatdecimal 字符串类型charvarchar 日期enum和set 数据类型分类 在MySQL数据库中&#xff0c;存在各种各样的数据类型&#xff1a; 针对于上述的这么多类型&#xff0c;本篇就对于这些类型的数据进行一一解释&#xff…

STM32--RC522学习记录

一&#xff0c;datasheet阅读记录 1.关于通信格式 2.读寄存器 u8 RC522_ReadReg(u8 address) {u8 addr address;u8 data0x00;addr((addr<<1)&0x7e)|0x80;//将最高位置一表示read&#xff0c;最后一位按照手册建议变为0Spi_Start();//选中从机SPI2_ReadWriteByte(ad…

javaSwing宿舍管理系统(三个角色)

一、 简介 宿舍管理系统是一个针对学校宿舍管理的软件系统&#xff0c;旨在方便学生、宿管和管理员进行宿舍信息管理、学生信息管理以及宿舍评比等操作。该系统使用 Java Swing 进行界面设计&#xff0c;分为三个角色&#xff1a;管理员、宿管和学生。 二、 功能模块 2.1 管…

面向中文大模型价值观的评估与对齐研究:“给AI的100瓶毒药”并解毒,守护AI纯净之心

面向中文大模型价值观的评估与对齐研究&#xff1a;“给AI的100瓶毒药”并解毒&#xff0c;守护AI纯净之心 1.简介 随着Large Language Models&#xff08;LLMs&#xff09;的快速发展&#xff0c;越来越多的人开始担心它们可能带来风险。因此&#xff0c;围绕大模型的“安全…

Collection与数据结构 数据结构预备知识(一) :集合框架与时间空间复杂度

1.集合框架 1.1 什么是集合框架 Java集合框架,又被称为容器,是定义在java.util包下的一组接口和接口实现的一些类.其主要的表现就是把一些数据放入这些容器中,对数据进行便捷的存储,检索,管理.集合框架底层实现原理其实就是各种数据结构的实现方法,所以在以后的学习中,我们会…

QT(3/22)

1>使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数&#xff0c;将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#…