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

news2024/11/17 15:59:39

【前置知识】

先要搞清楚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.coloradmin.cn/o/1541911.html

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

相关文章

基于Google云原生工程师的kubernetes最佳实践(三)

目录 三、集群管理 利用node affinity、taint等机制管理node 通过pod affinity/anti-affinity机制将pod分配到合适的node Node分级管理 从Qos角度将Pod分级 用namespace隔离不同的环境和用户 配置RBAC权限控制 1. 遵循最小权限原则 2. 使用 Role 和 ClusterRole 分离权…

计算机服务器中了faust勒索病毒怎么办,faust勒索病毒解密工具流程

网络是一把利剑&#xff0c;可以方便企业开展各项工作业务&#xff0c;为企业提供极大的便利&#xff0c;但随着网络技术的不断发展与应用&#xff0c;网络数据安全威胁也在不断增加&#xff0c;给企业的正常生产运营带来了极大困扰&#xff0c;近日&#xff0c;云天数据恢复中…

PointerLockControls 是 Three.js 中用于处理鼠标锁定状态下的相机控制的类。它允许用户通过鼠标移动来控制相机的旋转方向。

demo案例 PointerLockControls 是 Three.js 中用于处理鼠标锁定状态下的相机控制的类。它允许用户通过鼠标移动来控制相机的旋转方向。下面是它的详细讲解&#xff1a; 构造函数: PointerLockControls(object: Camera, domElement?: HTMLElement)object&#xff1a;THREE.Ca…

Linux 系统 快速卸载docker

(卸载前一定要做好相关数据的备份) 卸载&#xff1a; 第一种卸载方法 1、查询docker安装过的包&#xff1a; yum list installed | grep docker 2、删除安装包&#xff1a; yum remove docker-ce.x86_64 ddocker-ce-cli.x86_64 -y 3、删除镜像/容器等 rm -rf /var/lib/dock…

力扣面试150 x 的平方根 二分 换底法 牛顿迭代法 一题多解

Problem: 69. x 的平方根 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 袖珍计算器算法 class Solution {public int mySqrt(int x){if (x 0)return 0; // Math.exp(3)&#xff1a;e的三次方int ans (int) Math.exp(0.5 * Math.log(x));return (long) (an…

react native 键盘事件

在做修改密码功能是发现他的键盘第一次调起之后然后收起键盘焦点不会消失而且键盘也不会再调起来了 我门线引入需要的组件 import { StyleSheet, View, TextInput, Keyboard, TouchableWithoutFeedback, } from react-native; import React, {useEffect, useState, useRef} fr…

蓝桥杯真题:幸运数字

这道题可以用 integer.string&#xff08;&#xff09;求每个进制的数&#xff0c;但这里要每一位数相加&#xff0c;所以用这个方法会比较麻烦&#xff0c;如下 import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scan new Sc…

LeetCode 面试经典150题 14.最长公共前缀

题目&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 思路&#xff1a; 代码&#xff1a; class Solution {public String longestCommonPrefix(String[] strs) {if (strs.length 0) {return &…

吴恩达2022机器学习专项课程(一) 3.5 可视化成本函数

问题预览 为什么要可视化成本函数&#xff1f;可视化之后的成本函数是什么样子&#xff1f;如何在三维空间里通过w和b找到一个成本函数的值&#xff1f;如何在三维空间里找到成本函数的最小值&#xff1f; 解读 可视化成本函数&#xff1a;为了更加方便的看到不同的w和b&…

【短接笔记本或者台式机的CMOS针脚解决电脑开机无法启动BIOS无法进入问题】

为什么要执行短接笔记本或者台式机的CMOS针脚操作&#xff1f; 问题&#xff1a;可以解决如下图所示&#xff0c;技嘉小雕主板开机时按delete键无法进入BIOS主板界面&#xff0c;长时间等待之后依然无法进入BIOS主板界面&#xff0c;则判定为主板问题。此时短接CMOS针脚可清空…

【数据结构】考研真题攻克与重点知识点剖析 - 第 2 篇:线性表

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

ShardingSphere水平分表——开发经验(2)

1. 什么场景下分表&#xff1f; 数据量过大或者数据库表对应的磁盘文件过大。 Q&#xff1a;多少数据分表&#xff1f; A&#xff1a;网上有人说1kw&#xff0c;2kw&#xff1f;不准确。 1、一般看字段的数量&#xff0c;有没有包含text类型的字段。我们的主表里面是不允许有t…

Github 2024-03-24php开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-24统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10JavaScript项目1Nextcloud服务器:安全的数据之家 创建周期:2796 天开发语言:PHP, JavaScript协议类型:GNU Affero General Public…

计算机网络⑧ —— IP地址

IP位于TCP/IP参考模型的第三层&#xff0c;也就是⽹络层 ⽹络层的主要作⽤&#xff1a;实现主机与主机之间的通信&#xff0c;也叫点对点通信 问题1&#xff1a;⽹络层(IP)与数据链路层(MAC)有什么关系呢&#xff1f; MAC的作⽤&#xff1a;实现直连的两个设备之间通信。IP的…

包子凑数 蓝桥杯

关于这题的数学定理&#xff0c;如果 a,b 均是正整数且互质&#xff0c;那么由 axby&#xff0c;x≥0&#xff0c;y≥0 不能凑出的最大数是 &#xff1a;a*b-a-b 想不起来的时候&#xff0c;把能列出来的数据列出来找规律&#xff0c;不互质得数不符合题目所说 类似于力扣零钱…

【boost_search搜索引擎】1.获取数据源

boost搜索引擎 1、项目介绍2、获取数据源 1、项目介绍 boost_search项目和百度那种不一样&#xff0c;百度是全站搜索&#xff0c;而boost_search是一个站内搜索。而项目的宏观上实现思路就如同图上的思路。 2、获取数据源 我们要实现一个站内搜索&#xff0c;我们就要有这…

包含多个段的程序

文章目录 包含多个段的程序在代码段中使用数据在代码段中使用栈将数据、代码、栈放入不同的段 包含多个段的程序 在代码段中使用数据 考虑这样一个问题&#xff0c;编程计算以下8个数据的和&#xff0c;结果存在ax 寄存器中&#xff1a;0123H&#xff0c;0456H&#xff0c;07…

中性点接地问题的matlab仿真与分析

1、内容简介 略 81-可以交流、咨询、答疑 2、内容说明 略电力系统的中性点接地方式通常是按电压等级 的高低来进行选取的, 我国中压电网普遍采用的有 3 种方式 :不接地 、经消弧线圈接地和经电阻接地。 电力系统在正常运行时, 对不同的中性点接地方式及其差异, 基本上没有…

海外媒体宣发:十大国外中文网站-大舍传媒

十大国外中文网站 1、欧洲时报 覆盖欧洲且较具影响力的华文媒体 国外中文新闻网站&#xff0c;欧洲时报文化传媒集团旗舰日报《欧洲时报》旗下官方网站&#xff0c;总部设在法国巴黎&#xff0c;创刊于1983年&#xff0c;现已成为唯一发行覆盖全欧、发行量最大、最具影响力的华…

ubuntu上一款好用的串口工具screen

看名字&#xff0c;你猜他是什么&#xff1f; 安装 sudo apt install screen 然后将USB串口接到虚拟机&#xff0c;执行dmesg命令查看串口设备名&#xff1a; 测试&#xff1a; sudo screen /dev/ttyUSB0 115200确实很简单。