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加载和卸载的代码示例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ABLoadTest : MonoBehaviourprivate Dictionary<string, AssetBundle> abCache;private AssetBundle mainAB = null; //主包private AssetBundleManifest mainManifest = null; //主包中配置文件---用以获取依赖包private string basePathget#if UNITY_EDITOR || UNITY_STANDALONEreturn Application.dataPath + "/StreamingAssets/";
#elif UNITY_IPHONEreturn Application.dataPath + "/Raw/";
#elif UNITY_ANDROIDreturn Application.dataPath + "!/assets/";
#endifvoid Start()abCache = new Dictionary<string, AssetBundle>();var ab = LoadABTest();GameObject model = ab.LoadAsset<GameObject>("Cube");var b = Instantiate<GameObject>(model);// dosomethingAssetBundle LoadABTest()AssetBundle ab;string abName = "3dmodel.first";if (mainAB == null)mainAB = AssetBundle.LoadFromFile(basePath + "StandaloneWindows");mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//根据manifest获取所有依赖包的名称 固定APIstring[] dependencies = mainManifest.GetAllDependencies(abName);//循环加载所有依赖包for (int i = 0; i < dependencies.Length; i++)//如果不在缓存则加入if (!abCache.ContainsKey(dependencies[i]))//根据依赖包名称进行加载ab = AssetBundle.LoadFromFile(basePath + dependencies[i]);//注意添加进缓存 防止重复加载AB包abCache.Add(dependencies[i], ab);//加载目标包 -- 同理注意缓存问题if (abCache.ContainsKey(abName))Debug.Log($"have load abName");return abCache[abName];elseab = AssetBundle.LoadFromFile(basePath + abName);abCache.Add(abName, ab);Debug.Log($"new load abName");return ab;// Update is called once per framevoid Update()if(Input.GetKeyDown(KeyCode.A)) // 同步加载var ab = LoadABTest();GameObject model = ab.LoadAsset<GameObject>("Cube");var b = Instantiate<GameObject>(model);else if (Input.GetKeyDown(KeyCode.S))// 异步加载var ab = LoadABTest();StartCoroutine(LoadResAsyncTest(ab));else if (Input.GetKeyDown(KeyCode.D))// 单个卸载UnLoad("3dmodel.first");Debug.Log("have UnLoadAll 3dmodel.first");else if (Input.GetKeyDown(KeyCode.F))// 全部卸载UnLoadAll();Debug.Log("have UnLoadAll");private IEnumerator LoadResAsyncTest(AssetBundle ab)if (ab == null) yield return null;var model1 = ab.LoadAssetAsync<GameObject>("Cube");yield return model1;var async_model = Instantiate((GameObject)model1.asset);// dosomething//====================AB包的两种卸载方式=================//单个包卸载public void UnLoad(string abName)if (abCache.ContainsKey(abName))abCache[abName].Unload(false);//注意缓存需一并移除abCache.Remove(abName);//所有包卸载public void UnLoadAll()AssetBundle.UnloadAllAssetBundles(false);//注意清空缓存abCache.Clear();mainAB = null;mainManifest = null;

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

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

相关文章

Java工具类记录

HTML转word 相关依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency>import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi…

python接口自动化(二)--什么是接口测试、为什么要做接口测试(详解)

简介 上一篇和大家一起科普扫盲接口后&#xff0c;知道什么是接口&#xff0c;接口类型等&#xff0c;对其有了大致了解之后&#xff0c;我们就回到主题-接口测试。 什么是接口测试 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各…

“算力+运力”扇动双翼,制造算力时代的蝴蝶效应

8月18日-20日&#xff0c;第二届中国算力大会在宁夏银川成功举办。 今年以来&#xff0c;随着大模型、AIGC等新技术的火爆&#xff0c;站在舞台中央的算力承载了无尽的期待&#xff0c;发展数字经济需要以算力基础设施为前提&#xff0c;社会各界已经形成了共识。 与此同时&…

无涯教程-Android - DatePicker函数

Android Date Picker允许您在自定义用户界面中选择由日,月和年组成的日期。为此功能,android提供了DatePicker和DatePickerDialog组件。 在本教程中,我们将通过DatePickerDialog演示日期选择器的用法, DatePickerDialog是一个包含DatePicker的简单对话框。 为了显示DatePicker…

Leetcode110. 平衡二叉树

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 题解&#xff…

【Go 基础篇】探索Go语言中的Map:数据的魔法盒子

嗨&#xff0c;各位Go语言的探索者们&#xff01;在我们的编程世界中&#xff0c;总会有一些特殊的工具能够让我们的生活变得更加便捷。而在Go语言中&#xff0c;Map就是这样一种神奇的数据结构。它就像是一个魔法盒子&#xff0c;可以帮助我们高效地存储和操作键值对数据。本文…

vue3中axios的使用方法

在Vue 3中使用axios发送HTTP请求的方法与Vue 2中基本相同。首先&#xff0c;需要安装axios库&#xff1a; npm install axios然后&#xff0c;在Vue组件中引入axios&#xff1a; import axios from axios;接下来&#xff0c;可以在Vue组件的方法中使用axios发送HTTP请求。例如…

算法通关村14关 | 数据流中位数问题

1. 数据流中位数问题 题目 LeetCode295: 中位数是有序列表中间的数&#xff0c;如果列表长度是偶数&#xff0c;中位数是中间两个数的平均值&#xff0c; 例如:[2,3,4]的中位数是3&#xff0c; [2,3]中位数是&#xff08;23&#xff09;/ 2 2.5 设计一个数据结构&#xff1a; …

2023.9.1 简单认识 JVM

目录 JVM 内存划分 本地方法栈 虚拟机栈 程序计数器 堆区 元数据区 JVM 类加载机制 加载 验证 准备 解析 初始化 类被加载的几种情况&#xff08;懒汉模式 ---> 只要被用到才会被加载&#xff09; 双亲委派模型 JVM 内存划分 JVM 是一个应用程序&#xff0c;在…

用ChatGPT做一个Chrome扩展 | 京东云技术团队

用ChatGPT做了个Chrome Extension 最近科技圈儿最火的话题莫过于ChatGPT了。 最近又发布了GPT-4&#xff0c;发布会上的Demo着实吸睛。 笔记本上手画个网页原型&#xff0c;直接生成网页。网友直呼&#xff1a;前端失业了&#xff01; 但我觉着啊&#xff0c;真就外行看热闹…

JVM之堆和方法区

目录 1.堆 1.1 堆的结构 1.1.1 新生代&#xff08;Young Generation&#xff09; 1.1.2 年老代&#xff08;Old Generation&#xff09; 1.1.3 永久代/元空间&#xff08;Permanent Generation/Metaspace&#xff09; 1.2 堆的内存溢出 1.3 堆内存诊断 1.3.1 jmap 1.3.2…

Three.js添加阴影和简单后期处理

在Three.js中&#xff0c;可以使用渲染器的一些特性来实现阴影和后期处理效果。 添加阴影 要在Three.js中添加阴影效果&#xff0c;需要做以下几个步骤&#xff1a; 1.开启阴影 首先&#xff0c;要在渲染器中开启阴影&#xff1a; renderer.shadowMap.enabled true;2.设置…

minio文件服务器开启https

一、准备证书 你要有https安全证书&#xff0c;我的是适用于nginx的证书 私钥 xxxx.key 公钥 xxxx.pem 二、上传证书到minio服务器 然后看看你的minio docker 有没有把 /root/.minio 挂载在主机上&#xff0c;如果有那么把两个证书文件放在/root/.minio/certs目录里面。…

STM32启动模式详解

文章目录 前置知识1. 单片机最小系统组成2. BOOT电路3. 三种启动模式4. 存储器映射 从主FLASH启动从系统存储区启动从SRAM启动 前置知识 1. 单片机最小系统组成 一个单片机最小系统由电源、晶振、下载电路、BOOT电路、和复位电路组成。少一个单片机都启动不了。 2. BOOT电路 …

Linux基础(三)

一.系统基本优化 关闭selinux:getenforce 查看selinux状态setenforce 0 临时关闭vim /etc/sysconfig/selinux 永久关闭SELINUXdisabled 关闭防火墙&#xff1a;systemctl stop firewalld 临时关闭防火墙systemctl disable firewalld 永久关闭防火墙sys…

几种反序列化漏洞

1.PHP魔术方法 <?php class c {private $name hacker;function __construct() { // 构造方法&#xff0c;new时调用echo construct<br>;}function __serialize() { // 序列化时调用echo serialize<br>;return [hack];}function __unserialize($data) { // 反…

LeetCode-1005-K次取反后最大化的数组和-贪心算法

题目描述&#xff1a; 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数组 可能的最大和 。 …

多源最短路径算法:Floyd-Warshall算法分析

文章目录 图的邻接矩阵 一.Floyd-Warshall算法思想(基于动态规划)二.Floyd-Warshall算法接口笔记附录:单源最短路径--Bellman-Ford算法1.Bellman-Ford算法接口核心部分2.Bellman-Ford算法接口 图的邻接矩阵 namespace Graph_Structure {//Vertex是代表顶点的数据类型,Weight是…

python二级选择题必备

输出带有引号的字符串&#xff0c;可以使用转义字符\ 可以使用datatype()测试字符串的类型(没有datatype) 程序员可以调整的是异常(Exception)&#xff0c;开发者调整的是错误(Error) 序列类型是二维元素向量(一维)、元素之间存在先后关系&#xff0c;通过序号访问 Python的…

three.js(九):内置的路径合成几何体

路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…