• Unity AssetBundle(1):Assets打包和依赖(Dependencies)


    对Unity5.x后的AssetBundle依赖机制有了一点理解,创建了一个项目验证 github:GeWenL / AssetBundlePro AbScene.unity

    资源有哪些? Some common types of Asset

    assetbundle打包命令是 BuildPipeline.BuildAssetBundles ,格式有:

    引用:

    依赖的处理不当是导致 资源冗余 的重要原因。

    我的测试项目采用不压缩(UncompressedAssetBundle)的方式;

    4个Sprite纹理(不压缩),tex1-4; 单独打成不压缩的ab包,大小如下图所示。

    现在有5个prefab, sprite1.prefab 关联纹理tex1, sprite2.prefab 关联纹理tex2, sprite3.prefab 关联纹理tex3, sprite12.prefab 关联纹理tex1/tex2, sprite123.prefab 关联纹理tex1/tex2/tex3.

    将这5个prefab分别打ab包,prefabsp1、prefabsp2、prefabsp3、prefabsp12、prefabsp123.

    分成两种情况:

    这5个prefab ab包体积很小,仅仅关联了纹理ab包

    例如sprite1和sprite123两个prefab ab包的manifest文件,展示了关联的的tex1.png、tex2.png、tex3.png已经打在了对应的ab包中,因此要依赖对应的ab包,Dependencies是依赖ab列表。

    此时,仅加载sprite123.prefab(AssetBundle.LoadFromFile + bundle.LoadAsset + Instantiate):

    会发现使用tex1.png、tex2.png、tex3.png的Image对象上的图已经missing,显示也为错误的白色。原因是prefabsp123不包含图片这3张图片( UnityStudio 验证),只加载它,没有办法找到对应纹理。

    想要正常显示,需要提前加载tex1.png、tex2.png、tex3.png对应的ab包,例如提前加载tex1、tex2 ab包,效果如下:(tex1、tex2 正常显示,但tex3未加载也未正常显示)

    使用 UnityStudio 查看ab包能看出,prefabsp1不仅包含sprite1.prefab,还写入( written out to this single file )了Sprite-tex1.png,同样prefabsp12、prefabsp123也拥有一份自己的tex1.png,如下图所示。

    这种打包方式,被多次引用到的资源将在每个用到它的AssetBundle独自存在一份。也就是常常提到的资源冗余。

    核心是:避免资源冗余
    做法是:

    Unity中的AssetBundle

    AssetBundle的概念

    AssetBundle又称AB包,是Unity提供的一种用于存储资源的资源压缩包,是对Unity 初始Resources的一种扩展;一般使用的策略是把必须的资源和不需要更新的资源放在Resources文件夹下,其他的资源放在AssetBundle下面。

    Unity中的AssetBundle系统是对资源管理的一种扩展,通过将资源分布在不同的AB包中可以最大程度地减少运行时的内存压力,可以动态地加载和卸载AB包,继而有选择地加载内容。

    AssetBundle的优势

    1. AB包存储位置自定义,继而可放入可读可写的路径下便于实现热更新。
    2. AB包自定义压缩方式,可以选择不压缩或选择LZMA和LZ4等压缩方式,减小包的大小,更快的进行网络传输。
    3. 资源可分布在不同的AB包中,最大程度减少运行时的内存压力, 可做到即用即加载,有选择的加载需要的内容。
    4. AB包支持后期进行动态更新,显著减小初始安装包的大小,非核心资源以AB包形式上传服务器,后期运行时动态加载,提高用户体验。

    AssetBundle和Resources的比较

    AssetBundleResources
    资源可分布在多个包中所有资源打包成一个大包
    存储位置自定义灵活必须存放在Resources目录下
    压缩方式灵活(LZMA,LZ4)资源全部会压缩成二进制
    支持后期进行动态更新打包后资源只读无法动态更改

    AssetBundle的特性

    1. AB包可以存储绝大部分Unity资源但无法直接存储C#脚本,所以代码的热更新需要使用Lua或者存储编译后的DLL文件。
    2. AB包不能重复进行加载,当AB包已经加载进内存后必须卸载后才能重新加载。
    3. 多个资源分布在不同的AB包可能会出现一个预制体的贴图等部分资源不在同一个包下,直接加载会出现部分资源丢失的情况,即AB包之间是存在依赖关系的,在加载当前AB包时需要一并加载其所依赖的包。
    4. 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)

    AssetBundle全打包流程

    本次主要介绍Unity官方提供的AB包管理插件AssetBundle Browser 进行打包

    1. AssetBundleBrowser插件的获取 Unity 2019版本可以直接在Windows —>PackageManager里面找到此插件并直接安装

    2. 2020版本之后或其它版本可能在1方法中找不到此插件,可以通过去github搜索下载压缩包,将下载后的安装包解压到Unity工程的Packages文件夹下 (一定要解压)

    AssetBundleBrowser面板的使用

    正确获取到并安装完插件后,通过 Windows ----> AssetBundle Browser下打开AB包管理面板 一共有三个面板

    Configure面板 :能查看当前AB包及其内部资源的基本情况(大小,资源,依赖情况等)

    Build面板:负责AssetBundle打包的相关设置 按Build即可进行打包

    三种压缩方式

    NoCompression:不压缩,解压快,包较大,不建议使用。
    LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
    LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,一般建议使用这种。
    一般需要进行更改的设置即为图中勾选的相关选项设置。

    Inspect面板:主要用来查看已经打包后的AB包文件的一些详细情况(大小,资源路径等)
     


    3、设置资源所属的AssetBundle包

    在需要打包的资源的Inspector面板下方即可选择其应放在哪个AB包下,也可通过New新建AB包将资源放入,放入后再次Build打包即可将此资源打入相应的AB包中。

    AssetBundle加载和卸载的代码示例

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class ABLoadTest : MonoBehaviour
    5. private Dictionary<string, AssetBundle> abCache;
    6. private AssetBundle mainAB = null; //主包
    7. private AssetBundleManifest mainManifest = null; //主包中配置文件---用以获取依赖包
    8. private string basePath
    9. get
    10. #if UNITY_EDITOR || UNITY_STANDALONE
    11. return Application.dataPath + "/StreamingAssets/";
    12. #elif UNITY_IPHONE
    13. return Application.dataPath + "/Raw/";
    14. #elif UNITY_ANDROID
    15. return Application.dataPath + "!/assets/";
    16. #endif
    17. void Start()
    18. abCache = new Dictionary<string, AssetBundle>();
    19. var ab = LoadABTest();
    20. GameObject model = ab.LoadAsset<GameObject>("Cube");
    21. var b = Instantiate<GameObject>(model);
    22. // dosomething
    23. AssetBundle LoadABTest()
    24. AssetBundle ab;
    25. string abName = "3dmodel.first";
    26. if (mainAB == null)
    27. mainAB = AssetBundle.LoadFromFile(basePath + "StandaloneWindows");
    28. mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    29. //根据manifest获取所有依赖包的名称 固定API
    30. string[] dependencies = mainManifest.GetAllDependencies(abName);
    31. //循环加载所有依赖包
    32. for (int i = 0; i < dependencies.Length; i++)
    33. //如果不在缓存则加入
    34. if (!abCache.ContainsKey(dependencies[i]))
    35. //根据依赖包名称进行加载
    36. ab = AssetBundle.LoadFromFile(basePath + dependencies[i]);
    37. //注意添加进缓存 防止重复加载AB包
    38. abCache.Add(dependencies[i], ab);
    39. //加载目标包 -- 同理注意缓存问题
    40. if (abCache.ContainsKey(abName))
    41. Debug.Log($"have load abName");
    42. return abCache[abName];
    43. else
    44. ab = AssetBundle.LoadFromFile(basePath + abName);
    45. abCache.Add(abName, ab);
    46. Debug.Log($"new load abName");
    47. return ab;
    48. // Update is called once per frame
    49. void Update()
    50. if(Input.GetKeyDown(KeyCode.A)) // 同步加载
    51. var ab = LoadABTest();
    52. GameObject model = ab.LoadAsset<GameObject>("Cube");
    53. var b = Instantiate<GameObject>(model);
    54. else if (Input.GetKeyDown(KeyCode.S))// 异步加载
    55. var ab = LoadABTest();
    56. StartCoroutine(LoadResAsyncTest(ab));
    57. else if (Input.GetKeyDown(KeyCode.D))// 单个卸载
    58. UnLoad("3dmodel.first");
    59. Debug.Log("have UnLoadAll 3dmodel.first");
    60. else if (Input.GetKeyDown(KeyCode.F))// 全部卸载
    61. UnLoadAll();
    62. Debug.Log("have UnLoadAll");
    63. private IEnumerator LoadResAsyncTest(AssetBundle ab)
    64. if (ab == null) yield return null;
    65. var model1 = ab.LoadAssetAsync<GameObject>("Cube");
    66. yield return model1;
    67. var async_model = Instantiate((GameObject)model1.asset);
    68. // dosomething
    69. //====================AB包的两种卸载方式=================
    70. //单个包卸载
    71. public void UnLoad(string abName)
    72. if (abCache.ContainsKey(abName))
    73. abCache[abName].Unload(false);
    74. //注意缓存需一并移除
    75. abCache.Remove(abName);
    76. //所有包卸载
    77. public void UnLoadAll()
    78. AssetBundle.UnloadAllAssetBundles(false);
    79. //注意清空缓存
    80. abCache.Clear();
    81. mainAB = null;
    82. mainManifest = null;
  • 相关阅读:
    二维卡通数字人解决方案
    基于CC2530 E18-MS1-PCB Zigbee DIY作品
    locust性能测试工作概述
    js 事件参考
    LRU缓存替换策略及C#实现
    【每日一题】318. 最大单词长度乘积-2023.11.6
    LLM - 使用 Ollama + OpenWebUI 在 Linux 服务器中高效部署大语言模型
    摸鱼大数据——Kafka——kafka tools工具使用
    第四次作业
    Linux编辑器-vim使用
  • 原文地址:https://blog.csdn.net/st75033562/article/details/132629306