转载至 https://www.cnblogs.com/Roz-001/p/11237198.html
AssetBundle_介绍 (基于unity 2017 版本 --- 如要知晓最新资料建议去看官方文档)
一: AssetBundle的定义和作用
用处?
1,AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至是整个场景、可以在游戏运行时被加载。
2,AssetBundle自身保存着相互依赖的关系;---(AB包中后缀为manifest的文件夹中可被文本形式打开)
3,压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;
4,把一些可以下载的内容放在AssetBundle里面,可以减少安装包大小。---(便于游戏体验和更便于实时加载问题)
二: 什么是AssetBundle
可以归为两点
1,他是一个存在于硬盘上的文件。可以称之为压缩包,这个压缩包可以被认为是一个文件夹,里面包含了多个文件,
这些文件可以分为两类:Serializad file(序列化文件或流文件)和Resource file (源文件)。
a) Serializad file 资源是被打碎放在一个对象中,最后统一写进一个单独的文件(只有一个 类似Instance);
b) Resource file 某些二进制文件资源(如:图片 、声音等)被单独保存,方便快速的加载。
2,他是一个AssetBundle对象,我们可以通过代码从一个特定的压缩包加载出来的对象,这个对象包含了所有我们当初添加到这个文件压缩包里面的内容,我们可以通过这个对象加载出来使用。
三: AssetBundle 概念图
资源打包流程
资源使用流程
四 :AssetBundle 使用流程(简称AB)---“重要”
(基本设置)指定资源的AssetBundle属性 (xxxa/xxx)这里xxxa会生成目录,名字为xxx ;
如图:
选择一个需要打包的资源。
关于AB打包的面板和设置方法(图片内有说明)
//-----------------------------------------------------------------------------------------------------
A_使用编译器扩展---直接Build所有以及设置好要打包成AssetBundle的资料
当设置好后可以使用这个编译器扩展进行一次性全部打包模式
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateAssetBundles : MonoBehaviour
{
[MenuItem("AssetBundles/Build AssetBundles")] //特性
static void BuildAssetBundle()
{
string dir = "AssetBundles"; //相对路径
if(!Directory.Exists(dir)) //判断是否存在
{
Directory.CreateDirectory(dir);
}
BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
//-----------------------------------------------------------------------------------------------------
B_AssetBundle包_结构。
当设置好面板属性后,直接使用编译器(AssetBundle/Build AssetBundle)按键进行生成文件。创建后的样式
---本地项目文件夹下创建AB包文件夹
文件夹下的文件格式-----采取的是归类方式 (即 scene/map 这种形式)
最后AssetBundle的文件格式 ,因后缀没添加则只有文件名(注意manifest后缀的文件为管理文件,用于管理记录,为打包后自动生成的)
//-----------------------------------------------------------------------------------------------------
C_加载AB包和包里面的资源。----(需要注意的是带Async的API即是异步的方法不带则是同步方式)
首先介绍一下主要加载AB包的四种方式(即四种类型的API) :
1, 从文件中加载 AssetBundle.LoadFromFile 。
1 using System.Collections;
2 using UnityEngine;
3 using UnityEngine.Networking;
4
5 public class LoadFromFileExample : MonoBehaviour
6 {
7 private IEnumerator Start()
8 {
9 //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。
10 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。
11 AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12
13 AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/scene/map_001");
14
15 16 17
18 //这里需要注意的是 单独加载和加载所有压缩包内的对象处理方式
19
20 //加载单独的
21 GameObject panelPrefab = ab.LoadAsset<GameObject>("Plane"); //注意名字不能写错了
22
23 Instantiate(panelPrefab);//实例化资源
24
25 ////加载所有
26 //Object[] panelPrefab = ab.LoadAllAssets();
27
28 //foreach (var obj in panelPrefab)
29 //{
30 // Instantiate(obj);//实例化资源
31 //}
32
33 yield return null;
34 }
35 }
2、从内存中加载 AssetBundle.LoadFromMemoryAsync(注意是异步,去掉Asyns既是同步方法)
1 using System.Collections;
2 using UnityEngine;
3 using UnityEngine.Networking;
4
5 public class LoadFromFileExample : MonoBehaviour
6 {
7 private IEnumerator Start()
8 {
9 //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。
10 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。
11 AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12
13
14 string path = "AssetBundles/scene/map_01";
15
16 //LoadFromMemoryAsync 和 LoadFromMemory --内存读取
17 AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); //异步的方式
18 yield return request; //异步的方式 必须等待完成后才继续执行
19 AssetBundle ab = request.assetBundle;
20
21 //AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));//同步的方式
22
23 //使用资源
24 GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
25 Instantiate(gameObj);
26
27 yield return null;
28 }
29 }
3、第三种加载AB包的方式WWW(万维网) --WWW(万维网)对象方法可以从本地读取,也可以从服务器读取。
---需要注意的是这个方法在2017以后基本被UnityWebRequest(这个方法代替的是WWW远程读取)代替。做了一定程度的封装。
1 using System.Collections;
2 using UnityEngine;
3 using UnityEngine.Networking;
4
5 public class LoadFromFileExample : MonoBehaviour
6 {
7 private IEnumerator Start()
8 {
9 //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。
10 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。
11 //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12
13 //注意!!!
14 //www.LoadFromCacheOrDownload 这个方法是先下载存到cache的缓存空间内 然后在进行提取。
15 //如果第二次也进行下载一样的 则会在这个缓存空间内提取之前已经下载的数据
16 //开始下载前必须先判断是否准备好了,否则一直循环下去,等待准备好
17 while (!Caching.ready) //检查cache 缓存是否准备好了
18 yield return null;
19
20 //完整的路径---本地下载
21 //string allPath = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_01";
22 //WWW www = WWW.LoadFromCacheOrDownload(allPath, 1);
23
24 //远程服务器下载
25 WWW www = WWW.LoadFromCacheOrDownload(@"http://localhost/AssetBundles/scene/map_01", 1); //从远程服务器上下载AB包
26 yield return www;
27
28 //因万维网是非常复杂的,经常容易出现非常意外的错误,所以必须加入一个判断。
29 if(!string.IsNullOrEmpty(www.error)) //当什么都没有时
30 {
31 Debug.Log(www.error);
32 yield break; //跳出协程
33 }
34
35 AssetBundle ab = www.assetBundle;
36
37 //使用资源
38 GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
39 Instantiate(gameObj);
40
41 yield return null; //上述下载时没有加载相应的贴图材质。。。注意!!!
42 }
43 }
4、第四种Unity封装的UnityWebRequest对象---(专用于替代WWW的远程加载方式)
1 using System.Collections;
2 using UnityEngine;
3 using UnityEngine.Networking;
4
5 public class LoadFromFileExample : MonoBehaviour
6 {
7 private IEnumerator Start()
8 {
9 //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。
10 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。
11 //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12
13 //第四种远程加载方式---(专门用于替换WWW的远程加载方式)
14 //string uri = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_001";
15 string uri = @"http://localhost/AssetBundles/scene/map_001";
16 UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
17 yield return request.SendWebRequest(); //注意是异步方式所以必须等待他完成后再执行
18
19 //两种获取ab对象的方式
20 //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //第一种方法
21 AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第二种方法
22
23 //使用资源
24 GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
25 Instantiate(gameObj);
26
27 yield return null; //注意上述的远程加载方式是没有加载其依赖的资源
28 }
29 }
5_加载<AB包依赖项> ---(根据AB包文件夹下的 "AssetBundle文件以及AssetBundle.manifest文件")
1 using System.Collections;
2 using UnityEngine;
3 using UnityEngine.Networking;
4
5 public class Load : MonoBehaviour
6 {
7 //第一种是服务端加载AB资源包 和依赖包
8 private IEnumerator Start()
9 {
10 //从一个服务器下载一个AB包的管理文件AssetBundles 和 AssetBundles.manifest
11 string uri = @"http://localhost/AssetBundles/AssetBundles";
12 UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
13 yield return request.SendWebRequest();
14
15 //AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第一种方法
16 AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);//第二种方法
17 AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
18
19 string[] str = manifest.GetAllAssetBundles();
20
21 foreach(string s in str )
22 {
23
24 UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/" + s);
25 yield return uwr.SendWebRequest();
26 AssetBundle TmpAB = DownloadHandlerAssetBundle.GetContent(uwr);//第二种方法
27 Object[] obj = TmpAB.LoadAllAssets();
28
29 foreach (Object o in obj)
30 {
31 if(o is GameObject)
32 {
33 Instantiate(o);
34 }
35
36 print(obj.Length);
37 }
38
39 }
40
41
42
43 yield return null;
44 }
45
46
47
48 //第二种本地加载AB资源包 和依赖包
49 #region LoadAB.manifest
50 //private void Start()
51 //{
52 // //加载得到Manifest文件
53 // AssetBundle ab = AssetBundle.LoadFromFile("Assets /AssetBundle/AssetBundle");
54 // AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
55
56 // //从Manifest文件中得到所有的AB包的路径(包括依赖项)
57 // string[] str = manifest.GetAllAssetBundles();
58 // foreach (string s in str)
59 // {
60 // AssetBundle assetBundle = AssetBundle.LoadFromFile("Assets/AssetBundle/" + s);
61 // Object[] o = assetBundle.LoadAllAssets();
62 // foreach (Object temp in o)
63 // {
64 // if (temp is GameObject)
65 // {
66 // Instantiate(temp);
67 // }
68 // }
69 // }
70 //}
71 #endregion
72 }
小结:上述方法直接在场景中见一个空物体挂载其脚本即可(注意前提是AB包必须已经按相应方式创建好了)。
//=============================================================================================================
五:AssetBundle 打包时的分组(仅供参考)
1、逻辑实体分组:
a、一个UI界面或者所有UI界面一个包(这个界面里面所有的贴图和布局信息一个包);
b、一个角色或者所有角色一个包(这个角色里面的模型和动画一个包);
c、所有场景所共有的部分一个包(包括贴图和模型);
2、按照类型分组
所有的声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包。
3、按使用分组
把在某一时间内使用的所有资源打成一个包,可以按照关卡分,一个关卡所需要的所有资源包,包括角色、
贴图、声音等打成一个包,也可以按照场景分,一个场景所需要的资源一个包。
小结:
1、把经常更新的资源放在一个单独的包里、跟不经常更新的包分离。
2、把需要同时加载的资源放在一个包里面。
3、可以把其他包共享的资源放在一个单独的包里面。(做依赖,这样可以减少很多比较资源占用)
4、把一些需要同时加载的小资源打包成一个包。
5、如果对一个同一个资源有两个版本,可以考虑通过后缀来区分(如:v1 v2 v3 )(如unityAB_V1 、unityAV_V2);
//=============================================================================================================
六 : 依赖打包简介
小结:如图所示,其主要的特点是把模型预制体所使用的材质贴图进行整合,这样可以避免占用过多的内存资源,
在加载时也可以避免包过大使用的时间太长,同时避免了资源的重复加载。在需要加载时也可以通过依赖
关系进行逆向加载。
//=============================================================================================================
七: Build AssetBundle方法参数详解(BuildPipline.BuildAssetBundle)
1、Build的路径(只要是在硬盘上都可以的)
2、BuildAssetBundleOptions(枚举类型)
a)、BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但加载时间更长,
使用之前需要整体解压 。一旦被解压,这个包会使用LZ4重新压缩。使用资源的时候不需要整体解压
。在下载的时候可以使用LZMA算法。一旦它被下载了之后,它会使用LZ4算法保存到本地上。
b)、BuildAssetBundleOption.UncompressedAssetBundle (不压缩,包大,加载速度快)。
c)、BuildAssetBundleOption.ChunkBasedCompression:(使用LZ4算法,压缩率没有LZMA高,
但我们可以加载指定资源的不用解压全部);
注意:使用LZ4算法,可以获得可以跟不压缩相媲美的加载速度,而且比不压缩的文件要小。
3、BuildTarget:(选择Build出来的AB包需要的平台)
图解:
//=============================================================================================================
八:关于AssetBundle的卸载
首先为什么要把AB 包卸载了?其实也很简单,内存永远是有限的,当你转换一个场景或者关卡时,之前不需要的AB包所占用的内存是需要把它
释放掉的,这样才能让内存永远保持着一个健康的容量。
卸载主要有两个方面:
1、 减少内存使用,可以保证一个良好且健康的运行内存。
2、 有可能导致资源丢失问题。
所以一般什么时候卸载资源呢?
AssetBundle.Unload(true)卸载所有资源,即使有资源使用着(1,在关卡切换或场景切换时 2、资源没被用的时候调用);
AssetBundle.Unload(false)卸载所有没有被使用的资源。(这个适用时间比较多 ,可自行把控)。
个别资源怎么卸载,通过Resources.UnloadUnusedAssets();
当场景切换时,unity会自行执行(Resources.UnloadUnusedAssets()这个方法);
//=============================================================================================================
九:关于AssetBundle的文件效验(每个AB包中有一个manifest文件中就有一个CRC)
CRC、DM5、SHA1
相同点:
CRC、DM5、SHA1都是通过对数据进行计算,来生成一个效验值,该效验值用来效验数据的完整性。
不同点:
1、算法的不同。CRC采用多项式除法,MD5和SHA1使用的替换,轮转等方法。
2、效验值的长度不同。CRC效验值的长度基本跟其多项式有关系,一般为16位或32位,MD5是16个字节(128位);SHA1是20个字节(160位);
3、效验值的称呼不同。CRC一般叫做CRC值;MD5和SHA1一般叫哈希值(Hash)或散列值。
4、安全性不同。这里的安全性是指效验的能力,即数据的错误能通过效验位检测出来,CRC的安全性跟多项式有很大关系,相对于MD5和SHA1要弱很多;MD5的安全性很高,不过大概在04年的时候被山东大学的王小云**了;SHA1安全性最高。
(算法的过程一般是不可逆的,**即是逆向根据效验值推导出算法过程列表)
5、效率不同。CRC的计算效率很高;MD5和SHA1比较慢。
6、用途不同。CRC一般用作通信数据的效验,MD5和SHA1用于安全(Security)领域。比如文件效验、数字签名等。