unity asset store下载不了_Unity手游实战:从0开始SLG——资源管理系统-基础篇(三)AssetBundle原理...

先用一句话介绍一下AssetBundle吧。

AssetBundle系统提供了一种压缩文件的格式,可以把1到多个文件进行索引和序列化。

Unity项目在交付安装之后,会通过AssetBundle对不包含代码的资源进行更新。这就允许开发人员先提交一个小的应用程序包,将运行时内存压力降到最低,并有选择地加载针对不同终端用户设备优化后的内容。

3.1 AssetBundle结构

总的来说,AssetBundle就像传统的压缩包一样,由两个部分组成:包头和数据段。

包头包含有关AssetBundle 的信息,比如标识符、压缩类型和内容清单。清单是一个以Objects name为键的查找表。每个条目都提供一个字节索引,用来指示该Objects在AssetBundle数据段的位置。在大多数平台上,这个查找表是用平衡搜索树实现的。具体来说,Windows和OSX派生平台(包括IOS)都采用了红黑树。因此,构建清单所需的时间会随着AssetBundle中Assets的数量增加而线性增加。

数据段包含通过序列化AssetBundle中的Assets而生成的原始数据。如果指定LZMA为压缩方案的话,则对所有序列化Assets后的完整字节数组进行压缩。如果指定了LZ4,则单独压缩单独Assets的字节。如果不使用压缩,数据段将保持为原始字节流。

在Unity5.3之前,是无法对AssetBundle中单独Objects进行压缩的。因此,如果在5.3之前的Unity版本被要求从压缩的AssetBundle中读取一个或多个对象时,Unity必须解压整个AssetBundle。通常,Unity会缓存AssetBundle的解压缩副本,以提高在相同AssetBundle上的后续加载请求的加载性能。

3.2 加载AssetBundles

AssetBundles可以通过四个不同的API进行加载。但受限于两个标准,这四个API的行为是不同的。2个标准如下:

1、AssetBundles的压缩方式:LZMA、LZ4、还是未压缩的。

2、AssetBundles的加载平台。

而四个API分别是:

  • AssetBundle.LoadFromMemory(Async optional)
  • AssetBundle.LoadFromFile(Async optional)
  • UnityWebRequest's DownloadHandlerAssetBundle
  • WWW.LoadFromCacheOrDownload (on Unity 5.6 or older)

下面来详细讲一下4个API的区别。

3.2.1 AssetBundle.LoadFromMemory(Async)

Unity的建议是 不要使用这个API!

LoadFromMemory(Async) 是从托管代码的字节数组里加载AssetBundle。也就是说你要提前用其他的方式将资源的二进制数组加入到内存中。然后该接口会将源数据从托管代码字节数组复制到新分配的、连续的本机内存块中。

但如果AssetBundle使用了LZMA压缩类型,它将在复制时解压AssetBundle。而未压缩和LZ4压缩类型的AssetBundle将逐字节的完整复制。

之所以不建议使用该API是因为,此API消耗的最大内存量将至少是AssetBundle的两倍:本机内存中的一个副本,和LoadFromMemory(Async)从托管字节数组中复制的一个副本。

因此,从通过此API创建的AssetBundle加载的资产将在内存中冗余三次:一次在托管代码字节数组中,一次在AssetBundle的栈内存副本中,第三次在GPU或系统内存中,用于Asset本身。

注意:在Unity5.3.3之前,这个API被称为AssetBundle.CreateFromMemory。但功能没有改变。

3.2.2 AssetBundle.LoadFromFile(Async)

LoadFromFile是一种高效的API,用于从本地存储(如硬盘或SD卡)加载未压缩或LZ4压缩格式的AssetBundle。

在桌面独立平台、控制台和移动平台上,API将只加载AssetBundle的头部,并将剩余的数据留在磁盘上。

AssetBundle的Objects 会按需加载,比如加载方法(例如AssetBundle.Load)被调用或其InstanceID被间接引用的时候。在这种情况下,不会消耗过多的内存。

但在Editor环境下中,API还是会把整个AssetBundle加载到内存中,就像读取磁盘上的字节和使用AssetBundle.LoadFromMemoryAsync一样。

如果在Editor中对项目进行了分析,此API可能会导致在AssetBundle加载期间出现内存尖峰。但这不应影响设备上的性能,在做优化之前,这些尖峰应该在设备上重新再测试一一遍.

要注意,这个API只针对未压缩或LZ4压缩格式,因为前面说过了,如果使用LZMA压缩的话,它是针对整个生成后的数据包进行压缩的,所以在未解压之前是无法拿到AssetBundle的头信息的。

注意:这里曾经有过一个历史遗留问题,即在Unity5.3或更老版本的Android设备上,当试图从Streaming Assets路径加载AssetBundles时,此API将失败。这个问题已在Unity5.4中已经解决。

在Unity5.3之前,这个API被称为AssetBundle.CreateFromFile。其功能没有改变。

3.2.3 AssetBundleDownloadHandler

DownloadHandlerAssetBundle的操作是通过UnityWebRequest的API来完成的。

UnityWebRequest API允许开发人员精确地指定Unity 应如何处理下载的数据,并允许开发人员消除不必要的内存使用。使用UnityWebRequest下载AssetBundle 的最简单方法是调用UnityWebRequest.GetAssetBundle。

就实战项目而言,最有意思的类是DownloadHandlerAssetBundle。它使用工作线程,将下载的数据流存储到一个固定大小的缓冲区中,然后根据下载处理程序的配置方式将缓冲数据放到临时存储或AssetBundle缓存中。

所有这些操作都发生在非托管代码中,消除了增加堆内存的风险。此外,该下载处理程序并不会保留所有下载字节的栈内存副本,从而进一步减少了下载AssetBundle的内存开销。

LZMA压缩的AssetBundles将在下载和缓存的时候更改为LZ4压缩。这个可以通过设置Caching.CompressionEnable属性来更改。

如果将缓存信息提供给UnityWebRequest对象的话,一旦有请求的AssetBundle已经存在于Unity的缓存中,那么AssetBundle将立即可用,并且此API的行为将会与AssetBundle.LoadFromFile相同操作。

在Unity5.6之前,UnityWebRequest系统使用了一个固定的工作线程池和一个内部作业系统来防止过多的并发下载,并且线程池的大小是不可配置的。在Unity5.6中,这些安全措施已经被删除,以便适应更现代化的硬件,并允许更快地访问HTTP响应代码和报头。

3.2.4 WWW.LoadFromCacheOrDownload

这是一个很古老的API了,从Unity2017.1开始,就只是简单地包装了UnityWebRequest。因此,使用Unity2017.1或更高版本的开发者应该直接使用UnityWebRequest来工作。Unity已经放弃了对改接口的维护,并可能在未来的某个版本中移除。

所以下面说的这些内容只适合于Unity5.6或更老的版本。

WWW.LoadFromCacheOrDownload允许从远程服务器和本地存储加载对象。也可以通过文件//URL从本地存储加载文件。如果AssetBundle存在于Unitycache中,则此API的行为将与AssetBundle.LoadFromFile完全相同。

如果AssetBundle尚未缓存,则WWW.LoadFromCacheOrDownload会将从它的源文件读取AssetBundle。如果AssetBundle被压缩过,它会使用工作线程进行解压缩并写入缓存中。否则,它将通过工作线程直接写入缓存。

在缓存AssetBundle之后,WWW.LoadFromCacheOrDownload将从缓存的、解压缩的AssetBundle加载头信息。然后,和AssetBundle.LoadFromFile加载AssetBundle行为相同。

此缓存会在WWW.LoadFromCacheOrDownload和UnityWebRequest之间共享。一个API下载的任何AssetBundle也可以通过另一个API获得。

虽然数据将通过固定大小的缓冲区解压缩并写入缓存,但WWW对象会在本机内存中保留AssetBundle字节的完整副本。这个额外副本被保留的原因是因为要支持WWW.bytes字节属性。

由于在WWW对象中缓存AssetBundle的字节的内存开销,所以,实际项目开发中AssetBundles应该要保持较少的体积以便减少内存。

与UnityWebRequest不同的是,每次调用这个API都会产生一个新的工作线程。因此,在手机等内存有限的平台上,最好限定一次只能下载一个AssetBundle,以避免内存激增。而在其他平台也要小心创建过多的线程。

如果需要下载5个以上的AssetBundles,建议在脚本代码中创建和管理下载队列,以确保只有少数几个AssetBundle同时下载。

3.2.5 建议

1、一般来说,只要有可能,就应该使用AssetBundle.LoadFromFile。这个API在速度、磁盘使用和运行时内存使用方面是最有效的。

2、对于必须下载或热更新AssetBundles的项目,强烈建议对使用Unity5.3或更高版本的项目使用UnityWebRequest,对于使用Unity5.2或更老版本的项目使用WWW.LoadFromCacheOrDownload。

3、当使用UnityWebRequest或WWW.LoadFromCacheOrDownload时,要确保下载程序代码在加载AssetBundle后正确地调用Dispose。另外,C#的using语句是确保WWW或UnityWebRequest被安全处理的最方便的方法。

4、对于需要独特的、特定的缓存或下载需求的大项目,可以考虑使用自定义的下载器。编写自定义下载程序是一项重要并且复杂的任务,任何自定义的下载程序都应该与AssetBundle.LoadFromFile保持兼容。

3.3 从AssetBundles中加载Assets

到这里,我们已经能够获得AssetBundles了,那么接下来就是要从AssetBundles里获取Assets。

Unity提供了三个不同的API从AssetBundles加载UnityEngine.Objects,这些API都绑定到AssetBundle对象上,并且这些API具有同步和异步变体:

  • LoadAsset (LoadAssetAsync)
  • LoadAllAssets (LoadAllAssetsAsync)
  • LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)

并且这些API的同步版本总是比异步版本快至少一个帧(其实是因为异步版本为了确保异步,都至少延迟了1帧),异步加载每帧会加载多个对象,直到他们的时间切片切出。

加载多个独立的UnityEngine.Objects时应使用LoadAllAsset。并且只有在需要加载AssetBundle中的大多数或所有对象时,才应该使用它。与其他两个API相比,LoadAllAsset比对LoadAsset的多个单独调用略快一些。因此,如果要加载的Asset数量很大,但如果需要一次性加载不到三分之二的AssetBundle的话,则考虑将AssetBundle拆分为多个较小的包,再使用LoadAllAsset。

加载包含多个嵌入式对象的复合Asset时,应使用LoadAssetWithSubAsset,例如嵌入动画的FBX模型或嵌入多个精灵的sprite图集。也就是说,如果需要加载的对象都来自同一Asset,但与许多其他无关对象一起存储在AssetBundle中,则使用此API。

任何其他情况,请使用LoadAsset或LoadAssetAsync。

3.3.1 低层级的加载细节

Object加载是在主线程上执行,但数据从工作线程上的存储中读取。任何不触碰Unity系统中线程敏感部分(脚本、图形)的工作都将在工作线程上转换。例如,VBO将从网格创建,纹理将被解压,等等。

从Unity5.3开始,Object加载就被并行化了。在工作线程上反序列化、处理和集成多个Object。当一个Object完成加载时,它的Awake回调将被调用,该对象的其余部分将在下一个帧中对UnityEngine可用。

同步AssetBundle.Load方法将暂停主线程,直到Object加载完成。但它们也会加载时间切片的Object,以便Object集成不会占用太多的毫秒帧时间。应用程序属性设置毫秒数的属性为Application.backgroundLoadingPriority。

ThreadPriority.High: 每帧最多50毫秒

ThreadPriority.Normal: 每帧最多10毫秒

ThreadPriority.BelowNormal: 每帧最多4毫秒

ThreadPriority.Low: 每帧最多2毫秒。

从Unity5.2开始,加载多个对象时候,会一直进行直到达到对象加载的帧时间限制为止。假设所有其他因素相等,asset 加载API的异步变体将总是比同步版本花费更长的时间,因为发出异步调用和对象之间有最小的一帧延迟。

3.3.2 AssetBundle 依赖项

根据运行时环境的不同,使用两个不同的API自动跟踪AssetBundles之间的依赖关系。在UnityEditor中,可以通过AssetDatabaseAPI查询AssetBundle依赖项。AssetBundles分配和依赖项可以通过AssetImportAPI访问和更改。在运行时,Unity提供了一个可选的API,通过基于ScriptableObject的AssetBundleManifest API加载在AssetBundle构建过程中生成的依赖信息。

当一个或多个AssetBundle 的UnityEngine.Objects引用了一个或者多个其他AssetBundle 的UnityEngine.Objects,那么这个AssetBundle就会依赖于另外的AssetBundle。AssetBundles充当由它包含的每个对象的FileGUID和LocalID标识的源数据。

因为一个对象是在其Instance ID第一次被间接引用时加载的,而且由于一个对象在加载其AssetBundle时被分配了一个有效的Instance ID,所以加载AssetBundles的顺序并不重要。相反,在加载对象本身之前,重要的是加载包含对象依赖关系的所有AssetBundles。Unity不会尝试在加载父AssetBundle时自动加载任何子AssetBundle。

示例:

假设material A引用texture B。material A被打包到AssetBundle1中,texture B被打包到AssetBundle2中:

v2-81b7417547003a6206f37dc7e9576f8c_b.jpg

在本用例中,AssetBundle2必须在material A从AssetBundle1中加载之前先加载。

这并不意味着AssetBundle 2必须在AssetBundle 1之前加载,或者texture B必须从AssetBundle 2中显式加载。在将material A从AssetBundle 1加载之前加载AssetBundle 2就足够了。

简单来说就是AssetBundle之间的加载没有先后,但是Asset的加载有。

有关AssetBundle依赖项的详细信息,请参阅手册页。地址:https://docs.unity3d.com/Manual/AssetBundles-Dependencies.html?_ga=2.168691873.1408835506.1571651191-1030292064.1564583003

3.3.3. AssetBundle manifests

当使用BuildPiine.BuildAssetBundles API执行AssetBundle构建管线时,Unity会序列化一个包含每个AssetBundle依赖项信息的对象。此数据存储在单独的AssetBundle中,其中包含AssetBundleManifest类型的单个对象。

此Asset将存储在与构建AssetBundles的父目录同名的AssetBundle中。如果一个项目将其AssetBundles构建到位于(Projectroot)/Build/Client/的文件夹中,那么包含清单的AssetBundle将被保存为(Projectroot)/build/client/Client.manifest。

包含Manifest的AssetBundle可以像任何其他AssetBundle一样加载、缓存和卸载。

AssetBundleManifest对象本身提供GetAllAssetBundles API来列出与清单同时构建的所有AssetBundles,以及查询特定AssetBundle的依赖项的两个方法:

  • AssetBundleManifest.GetAllDependencies返回AssetBundle的所有层次依赖项,其中包括AssetBundle的直接子级、其子级的依赖项等。
  • AssetBundleManifest.GetDirectDependations只返回AssetBundle的直接子级

请注意,这两个API分配的都是字符串数组。因此,最好是在性能要求不敏感的时候使用。

3.3.4. 建议

在多数情况下,最好在玩家进入应用程序的性能关键区域(如主游戏关卡或世界)之前加载尽可能多的所需对象。这在移动平台上尤为重要,因为在移动平台上,访问本地存储的速度很慢,并且在运行时加载和卸载对象会触发垃圾回收。

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

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

相关文章

matlab中GUIDE的UItable居中方法

需要借助JAVA,代码示意如下: import javax.swing.*; %导入javax.swing类 table findjobj(handles.uitable1); %需要findjobj.m文件,matlab中是没有的 table1 get(table,Viewport); jtable get(table1,View); renderer jtable.getCellRe…

MySQL Workbench运行脚本

首先在SCHEMAS区域右击,选择创建“create schema” 填入自定义名称,点击“apply” 在弹出来的框中点击“apply”,再在弹出来的框中点击finish 点击菜单栏“file”——“run SQL script”,选择sql文件,在下面选择刚刚创…

自动驾驶事故权威揭秘:算法和软件错误太多

本文来源:AutoR智驾自动驾驶发展就好比是登月计划。从传感器到人工智能,经典的电子供应链已经形成了一个协作矩阵,致力于实现自动驾驶车辆的安全性。为此,还需进行大量硬件和软件开发工作,以确保驾驶员、乘客和行人受到…

MySQL新建数据库和表

首先在MySQL Workbench上(如果没有的话建议安装一个)新建一个数据库 首先在SCHEMAS区域右击,选择创建“create schema” 填入自定义名称,点击“apply”,这里我命名为crashcourse 在弹出来的框中点击“apply”&#xf…

【微读书】《人工智能颠覆未来战争》连载之一:机器战胜人类?——AlphaGo人机对战的启示...

来源:中国指挥与控制学会编者按目前,人工智能技术正加速向军事领域渗透,军事智能化既面临千载难逢的发展机遇,也面临前所未有的挑战。如何加强风险研究和预判,防范重大风险,已经客观而现实地摆在我们面前。…

《崛起的超级智能》入选中国好书2019年7月榜单

来源:中国好书中国好书评选活动由中国图书评论学会主办,旨在通过好书推介传递正能量,推动和引导全民阅读。中国图书评论学会是由中宣部出版局创办、国家新闻出版广电总局主管的国家一级学会。自2014年举办首届年度好书盛典至今,“…

.net函数查询_SQL查询语句总是先执行SELECT?你们都错了!

很多 SQL 查询都是以 SELECT 开始的。不过,最近我跟别人解释什么是窗口函数,我在网上搜索”是否可以对窗口函数返回的结果进行过滤“这个问题,得出的结论是”窗口函数必须在 WHERE 和 GROUP BY 之后,所以不能”。于是我又想到了另…

大数据世界要熟悉的5门语言

大数据世界要熟悉的5门语言课程 Python OpenStack Java Hadoop Scala Spark Shell Linux SQL DB JS 华丽分割线 转载于:https://www.cnblogs.com/TendToBigData/p/10501438.html

知识图谱嵌入(KGE):方法和应用的综述

来源:专知导读本文主要是参考《Knowledge Graph Embedding: A Survey of Approaches and Applications》和刘知远的《知识表示学习的研究与进展》做的总结,主要介绍了最近关于知识图谱嵌入所涉及到的研究方法,主要从融合事实信息、融合附加信…

支持向量机matlab代码程序_支持向量机(SVM)小结

什么是SVM?SVM(全称:Support Vector Machine)支持向量机,这只是它的名称,向量就是和我们以前学过的向量一样(下文有介绍),它可以有效解决分类问题(我们只讨论分类问题),何为分类呢?顾名思义&…

俄罗斯拟明年在36万台华为平板安装“极光”操作系统

来源:环球时报据路透社报道,有消息人士表示,俄罗斯政府已经开始与华为公司就36万台平板电脑安装俄罗斯自己研发的操作系统(OS)"极光"(Aurora,也称奥罗拉)的一项计划展开谈判。路透社表示&#xf…

mysql 命令 kill_MySQL之死锁检测

最近,笔者在查看线上服务日志时,发现spring大量异常,异常中都显示了同样的报错信息,信息如下。Deadlock found when trying to get lock; try restarting transaction调研之后发现是mysql发生了死锁,这也是笔者第一次遇…

干货丨清华大学天机芯团队赵明国:《基于自然动力学的机器人控制——无人驾驶自行车及被动行走》...

来源: 机器人大讲堂8月1日,清华大学依托精密仪器系的类脑计算研究中心施路平教授团队在《自然》(Nature)杂志上发表了一篇封面文章,发布了一项最新研究成果——类脑计算芯片“天机芯”。同时,搭载天机芯&am…

判断随机抽取代码_问卷调查:定量研究中的抽样问题(2)- 非随机抽样介绍

所谓抽样,就是从我们需要研究的所有目标群体中,按照某种原则,挑选出一定量的样本,用他们的研究结果,代表目标群体整体结果。既然,抽样的目的是通过对一部分被选择的样本来推断总体,就要求我们抽…

欧洲估值最高的5家人工智能创业公司

来源:资本实验室今年初,据伦敦风险投资公司MMC的调查,四成自称为人工智能公司的欧洲创业公司实际上并未在核心业务中涉及到人工智能,人工智能仅为吸引投资的漂亮外衣。这一数据发布后,激起了轩然大波,不仅引…

keras安装_代码详解:构建一个简单的Keras+深度学习REST API

在本教程中,我们将介绍一个简单的方法来获取Keras模型并将其部署为REST API。本文所介绍的示例将作为你构建自己的深度学习API的模板/起点——你可以扩展代码,根据API端点的可伸缩性和稳定性对其进行定制。具体而言,我们将了解: 如…

马云对话马斯克(全文):要警惕AI?该移民火星?如何更长寿?马化腾反对产业割裂和技术脱钩...

来源:未来论坛今天(8月29日),2019年世界人工智能大会在上海召开,500余位国内外顶尖高校、行业领军企业、国际组织的重要嘉宾,全球AI知名企业领袖齐聚于此。本次大会以“智联世界,无限可能”为主…

给plt.axvline设置图例(label)

plt.axvline的其中一个参数是label,用于给这条垂直线设置标签。但加上后就是不显示这个这个图例,代码如下: sns.kdeplot(data) plt.axvline(-2, colorr, linestyle--, label0.9) plt.show() 原因会因为没有加这一句: plt.legend…

python excel 转json_Python办公自动化| word 表格转excel

之前写过一篇 Python办公自动化 | 批量word报告生成工具 ,有小伙伴提出了逆向需求,即:从批量word中获取内容并写入excel,需求背景是汇总一些材料,举例:实习鉴定表、个人简历、档案等。实际需求是这样的&…

python在图中画一条垂直线(matplotlib)

matplotlib.pyplot.axvline https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axvline.html?highlightaxvline#matplotlib.pyplot.axvline 用法: plt.axvline(x, colorr, linestyle--, labelxxx) plt.legend()