Unity中的资源管理-AssetBundle(2)

2024-03-08 06:40

本文主要是介绍Unity中的资源管理-AssetBundle(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文分享Unity中的资源管理-AssetBundle(2)

在上一篇文章中, 我们介绍了Ab的基础知识, 并了解到如何构建Ab, 最后还给出了几种不同的Ab管理方案.

今天我们接着聊聊Ab的加载和卸载.

Ab的使用总的来说比较简单, 前提是我们不操心加载好的Ab和从Ab中加载出来的资材, 但整个资源管理的难点就在于此.

目前我们只是谈论Ab最核心的使用而不涉及到基于此的各种资源管理方案. 这部分会在后面的文章给出.

好了, 下面开始今天的内容.

Ab的加载和使用

基本的加载接口

Unity提供了Ab的同步和异步加载方式. 两者都是十分简单的. 总体遵循: 先加载Ab, 然后从Ab中加载资材, 清理资材, 卸载Ab的流程.

这里以上篇文章打包出来的Ab为例:

同步加载如下:

var ab = AssetBundle.LoadFromFile("Assets/Output/AssetBundle/AllAb/prefab");
var obj = ab.LoadAsset<GameObject>("obj.prefab");
Instantiate(obj);

异步加载如下:

void Start() {StartCoroutine(LoadAsync());
}IEnumerator LoadAsync() {var path = "Assets/Output/AssetBundle/AllAb/prefabs";var request = AssetBundle.LoadFromFileAsync(path);yield return request;var obj = request.assetBundle.LoadAsset<GameObject>("obj.prefab");Instantiate(obj);
}

上面两种方式都是从本地加载, Unity还提供了从网络加载, 准确的说是从URL加载, 而URL是包括本地的.

从URL加载Ab

URL是统一资源定位符的意思, 支持下面各种协议:

  • http://

  • https://

  • file://(访问本地文件)

  • ftp://(只支持匿名账号)

从Unity5.3以上, WWW相关接口被弃用, 而使用新的UnityWebRequest相关接口, 我们这里就不再介绍WWW的方式了.

从URL加载Ab比起从本地加载略微复杂一点点. 所有相关接口基本都是异步的, 你也可以是当做同步使用, 自己定制.

首先介绍的是从URL加载资源, 包括所有的资源(这里依然从本地加载, 如果是网络, 只需要切换协议即可):

IEnumerator LoadWebRequest() {var request = UnityWebRequest.Get("file://C:/resourceManage/Assets/Output/AssetBundle/AllAb/prefabs");yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError) {Debug.LogError("网络错误!" + request.error);yield break;}var data = request.downloadHandler.data;var ab = AssetBundle.LoadFromMemory(data);var obj = ab.LoadAsset<GameObject>("obj.prefab");Instantiate(obj);
}

这种方式加载出来的是bytes, 还需要各种资源提供的接口来构造资源, 比如AssetBundle.LoadFromMemory.

基于第一种方式, 我们可以替换downloadHandler, 告知下载的资源类型, 后续即可直接使用, 如下:

IEnumerator LoadWebRequest2() {var request = UnityWebRequest.Get("file://C:/resourceManage/Assets/Output/AssetBundle/AllAb/prefabs");// var handler = new DownloadHandlerAssetBundle(request.url, 2958429916);var handler = new DownloadHandlerAssetBundle(request.url, 0);request.downloadHandler = handler;yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError) {Debug.LogError("网络错误!" + request.error);yield break;}var ab = handler.assetBundle;var obj = ab.LoadAsset<GameObject>("obj.prefab");Instantiate(obj);
}

这里提供DownloadHandlerAssetBundle作为downloadHandler, 第二个参数为资源的crc, 这可以让Unity为我们做资源效验, 如果传入0则不效验.

DownloadHandlerAssetBundle告知要下载的资源为Assetbundle, 还可以提供:

  • DownloadHandlerTexture: 纹理
  • DownloadHandlerAudioClip: 声音
  • DownloadHandlerBuffer: 缓存
  • DownloadHandlerFile:文件
  • DownloadHandlerScript:自定义

downloadHandler是一种Helper类, 会附加到UnityWebRequest对象上, 在接收到数据之后做一些跟类型紧密相关的操作, 以供后续方便使用.

最后, 针对AssetBundle, Unity还提供了更加便利的封装接口UnityWebRequestAssetBundle:

IEnumerator LoadWebRequest3() {var request = UnityWebRequestAssetBundle.GetAssetBundle("file://C:/resourceManage/Assets/Output/AssetBundle/AllAb/prefabs", 0);yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError) {Debug.LogError("网络错误!" + request.error);yield break;}var ab = DownloadHandlerAssetBundle.GetContent(request);var obj = ab.LoadAsset<GameObject>("obj.prefab");Instantiate(obj);
}

使用GetAssetBundle接口请求, 使用DownloadHandlerAssetBundlehandler进行处理.

压缩方式决定使用方式

根据Ab的压缩方式的不同, 我们对于Ab有不同的使用方式.

上一篇文章介绍过, Unity提供了LZMALZ4两种压缩方式.

其中LZMA是基于流的压缩方式, 也就是是数据整体按照顺序一一排列, 输出为数据流之后再进行压缩的方式, 而这样压缩的效率比较高, 包体会比较小.

因为是按照顺序排列, 所以在使用时也有顺序要求, 也就是说, 我们在使用这种压缩方式出来的包时, 需要的流程为:

整体加载Ab包, 整体解压所有资材, 然后从内存中取用资材, 此时整个Ab中包含的资材都在内存中, 而不管我们使用不使用, 或者什么时候使用.

这就会造成首次加载和解压Ab时比较耗时, 且内存占用也比较高. 当然, 好处也是显而易见的, 所有的资材都已经准备好了, 我们在使用的时候不需要进行IO操作, 会有比较流畅的体验.

为了解决内存占用过高的问题, Unity会在Ab初次解压之后, 使用LZ4重新压缩并存储在磁盘上, 下次加载加使用LZ4方式解压使用.

一般在需要整体加载的资材使用这种压缩方式, 比如一整个模型, 不会使用单独的资材, 只要使用必然是整个一起使用.

LZ4是基于块的压缩方式, 就是将资材一块一块的压缩后组合起来, 没有顺序要求, 压缩比也不高, 但是在使用的时候会带来巨大的好处:

可以只加载在Ab头, 在实际使用的时候再解压具体的资材, 资材不用的时候也可以卸载, 也就是说加载资源超级快, 内存占用也比较小. 当然, 因为是即用即解压, 在首次解压某个资材的时候, 会有轻微的卡顿, 具体视资材大小而定.

总体上来说, 两种压缩方式各有千秋, 在Unity的发展历程中, 主要面向中小型项目(当然, 大型项目支持也是很好的), 所以默认的压缩方式是LZMA, 中小型项目资源不是很多, 可以在一开始就走一次Loading, 加载好所有的资源, 在使用过程中得到比较好的体验.

使用LZ4的加载速度与不压缩时区别不大, 额外的优势是减小了磁盘占用大小.

内存占用和卸载

Unity将Ab相关的内容划分为三个部分:

  • Asset: 资材
  • AssetBundle: 资材包
  • Object: 实例化对象(针对某些类型的资材)

总体的流程为: 使用各种方式加载Ab, 然后从Ab中加载资材, 如果资材支持实例化则实例化之后使用, 如果不支持则直接使用.

加载资材后, 有些资材可以被引用着使用(内存中只存在一份), 比如纹理, 材质, 声音等. 而有些资材需要复制后使用(内存中存在多份), 比如预制, 模型等.

所以资材的使用可以分为引用和实例化, 整个内存分为: Ab所占内存, 资材所占内存, 实例化对象所占内存.

知道了以上的知识, 我们同时就知道如何卸载了, 反过来即可, 先摧毁实例化对象, 然后释放资材, 最后释放Ab. 对应的接口分别为:

  • Destroy: 摧毁实例化对象
  • Resources.UnloadAsset: 卸载非实例化资材, 预制, 模型, 游戏对象等需要实例化的资材不能使用
  • Resources.UnloadUnusedAssets: 卸载所有不使用的资材
    • 不使用指不存在强引用, 比如变量持有, 对象引用等
    • 不需要实例化的资材, 只需要无引用即可
    • 需要实例化的资材, 还需要先销毁其实例化的对象
  • AssetBundle.Unload(true or false): 卸载Ab, 参数代表是否同时卸载所有的资材和其实例化出来的对象, 如果为true且还存在资材或者对象引用, 则会出现资材丢失, 即粉色现象.
  • 如果是通过URL相关接口加载Ab, 则可能会在内存中存在一份资源的原始数据, 根据不同的接口会有不同的表现.

下面给出网上比较常见的两张图, 基本上就是上面介绍的内容:

在这里插入图片描述
在这里插入图片描述

图片中已经表达的很清楚了, 这里简单的总结几句:

  • 使用URL相关接口(包括WWW, UnityWebRequest), 有些会先在内存中构造一份资源数据, 然后再从这个数据中构造Ab, 有些则不会
  • 加载Ab后, 会在内存中存在一份Ab的数据, 根据压缩方式的不同, 这份数据大小不一
总结

Ab的加载本身十分简单, 困难的点在于加载和使用后其内存分布, 并且如何在适当的实际进行卸载.

大家可能有些察觉, 从今天的内容开始慢慢开始复杂起来了. 不过不用担心, 我们先将理论做简单的介绍, 后续会更多的使用实例来论证这些内容, 两相印证后可能会有比较好的理解效果.

可能有些同学对内存部分还是有些云里雾里, 不用担心, 我们会在下一篇文章对Ab的内存占用进行分析, 同时顺便介绍内存分析工具和方法, 感兴趣的同学可以持续关注.

好了, 今天的内容就是这些, 希望对大家有所帮助.

这篇关于Unity中的资源管理-AssetBundle(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/786332

相关文章

【Python知识宝库】上下文管理器与with语句:资源管理的优雅方式

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、什么是上下文管理器?二、上下文管理器的实现三、使用内置上下文管理器四、使用`contextlib`模块五、总结 前言 在Python编程中,资源管理是一个重要的主题,尤其是在处理文件、网络连接和数据库

Unity Post Process Unity后处理学习日志

Unity Post Process Unity后处理学习日志 在现代游戏开发中,后处理(Post Processing)技术已经成为提升游戏画面质量的关键工具。Unity的后处理栈(Post Processing Stack)是一个强大的插件,它允许开发者为游戏场景添加各种视觉效果,如景深、色彩校正、辉光、模糊等。这些效果不仅能够增强游戏的视觉吸引力,还能帮助传达特定的情感和氛围。 文档

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光 一,前言二,资源包内容三,免费获取资源包 一,前言 在创意的世界里,每一个细节都能决定一个项目的独特魅力。今天,要向大家介绍一款令人惊艳的粒子效果包 ——Super Confetti FX。 二,资源包内容 💥充满活力与动态,是 Super Confetti FX 最显著的标签。它宛如一位

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客  这节就是真正的存储数据了   理清一下思路: 1.存储路径并检查 //2进制文件类存储private static string Data_Binary_Pa

Unity Adressables 使用说明(一)概述

使用 Adressables 组织管理 Asset Addressables 包基于 Unity 的 AssetBundles 系统,并提供了一个用户界面来管理您的 AssetBundles。当您使一个资源可寻址(Addressable)时,您可以使用该资源的地址从任何地方加载它。无论资源是在本地应用程序中可用还是存储在远程内容分发网络上,Addressable 系统都会定位并返回该资源。 您

Unity Adressables 使用说明(六)加载(Load) Addressable Assets

【概述】Load Addressable Assets Addressables类提供了加载 Addressable assets 的方法。你可以一次加载一个资源或批量加载资源。为了识别要加载的资源,你需要向加载方法传递一个键或键列表。键可以是以下对象之一: Address:包含你分配给资源的地址的字符串。Label:包含分配给一个或多个资源的标签的字符串。AssetReference Obj

理解C++全局对象析构顺序与 IPC 资源管理:避免 coredump

文章目录 0. 概述1. 问题背景2. 问题分析3. 解决方案:手动释放资源4. 深入剖析:为什么手动调用 `reset()` 有效?5. 延伸思考:如何避免全局对象带来的问题?6. 总结 0. 概述 在编写 C++ 程序时,使用全局或静态对象有时可能会导致不可预期的崩溃(如 coredump)。这类崩溃通常源于对象的析构顺序、资源的管理方式,以及底层资源(如 IPC 通道或共

在Unity环境中使用UTF-8编码

为什么要讨论这个问题         为了避免乱码和更好的跨平台         我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本,默认是看不到在VS中的编码格式,下面我介绍一种简单快

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(2) (*****生成数据结构类的方式特别有趣****)-CSDN博客 做完了数据结构类,该做一个存储类了,也就是生成一个字典类(只是声明)  实现和上一节的数据结构类的方式大同小异,所