AssetBundle 资源打包 加载 卸载

 

 

1 给要打包的资源设置标记,表示对应的包名:

  AssetBundle 资源打包 加载 卸载_第1张图片

 

2 Unity5 AssetBundle不需要我们来管理引用关系了

 

 

 

3 可以使用代码批量设置包名

 AssetImporter ai = AssetImporter.GetAtPath(assetPath);
 i.assetBundleName = xxx;
 ai.assetBundleVariant = xxx;

 

 

 

4 Build the AssetBundles

Create a folder called Editor in the Assets folders, and place a script with the following contents in the folder:

using UnityEditor;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]//菜单选项
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";//打包到哪里
        if(!Directory.Exists(assetBundleDirectory))
{
    Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }
}

 

 

BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);

是主要的打包函数。

其中第二个参数,

BuildAssetBundleOptions

BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载时间更长。使用之前需要整体解压。一旦被解压,这个包会使用LZ4重新压缩。使用资源的时候不需要整体解压。在下载的时候可以使用LZMA算法,一旦它被下载了之后,它会使用LZ4算法保存到本地上。

BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快

BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部。

注意使用LZ4压缩,可以获得可以跟不压缩想媲美的加载速度,而且比不压缩文件要小。

https://docs.unity3d.com/Manual/AssetBundles-Building.html

 

调用该函数,unity会自动根据资源的标签进行打包,而且是增量打包,

  a.对于资源没有变更的bundle包,不会触发重新打包;
  b.资源没变,即使生成目录下的bundle包被删除了,unity也不会重新打包;
  c.生成目录下的bundle包对应的manifase被删了,会重新打包;
  d.可以使用BuildAssetBundleOptions.ForceRebuildAssetBundle参数触发强制重新打包。
 

 

5  生成的bundle包资源目录:

 

 

  AssetBundle 资源打包 加载 卸载_第2张图片

  StreamingAssets:一个AssetBundle包,内含AssetBundleManifest类型的Asset,记录了所有bundle包及相互间的依赖关系。
    运行时需要首先加载这个AssetBundleManifest,然后根据其提供的depence信息加载依赖的bundle包。
  StreamingAssets.manifest:全局manifest,全局manifest的名字和打包生成的目录同名,不是固定的,这里是生成在StreamingAssets目录下。
  Cube.assetbundle:资源bundle。

  Cube.assetbundle.manifest:每个资源自己的manifest,与bundle一一对应,只是用来做增量build,运行时根本不需要。

 

^_^场景打包成AssetBundle资源和普通资源打包有所区别。

这是一个普通的assetbundle

AssetBundle 资源打包 加载 卸载_第3张图片

The Scene AssetBundle is different to normal AssetBundles, in that it is optimized for stream loading of a Scene and its content.

Scene AssetBundle略有不同,为

加载场景Scene AssetBundle用到的接口:

SceneManager.LoadScene()或者SceneManager.LoadSceneAsync()

第二个参数决定了是否销毁之前加载的GameObject

 

 

    manifest文件里面定义了使用的资源和依赖:

AssetBundle 资源打包 加载 卸载_第4张图片

 

 

加载Manifests文件可以处理资源的依赖

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);

AssetBundleManifest manifest =

assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

string[]dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundleyou want the dependencies for.

foreach(string dependency in dependencies)

{

    AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));

 

 

 

6压缩格式
  (1)LZMA:默认压缩格式,压缩比大,省空间,使用前需要解压整个压缩包;
  (2)LZ4:5.3版本新增, 40%–60% 的压缩率,开启BuildAssetBundleOptions.ChunkBasedCompression打包参数即可。
    LZ4算法是“基于块”的,因此当对象从一个LZ4压缩包加载时,仅用于该对象的相应块会被解压,不需要解压整个包。

    所以LZ4和不压缩资源一样,都可以不解压,而直接读取包中的资源的。

 

AssetBundle加载方式对比

  主要的加载方式有以下四种,前两种还兼具下载的功能,后两种都有对应的异步接口:

        使用哪一种方法取决于bundle的提供形式:

 

  (1)WWW.LoadFromCacheOrDownload:走本地cache,没有就下载并解压(然后再LZ4压缩),有就用;
    如果没有缓存,对于未压缩的和LZ4压缩的AssetBundle包,unity会直接把它们拷贝到缓存目录里面,对于LZMA压缩的,会先解压然后重新压缩成LZ4格式,然后缓存它。可以通过Caching.compressionEnabled控制是否压缩缓存。
  (2)LoadFromFile:最快的方式,区别于4.x版本,可以直接使用压缩资源;
    如果是UnCompress或LZ4,直接从disk读取

 

    如果是LZMA,会先解压到memory,然后读取

 

 

For users intending to load from local storage, you’ll be interested in the AssetBundles.LoadFromFile API. Which looks like this:

public class LoadFromFileExample extends MonoBehaviour {
    function Start() {
        var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
        if (myLoadedAssetBundle == null) {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset.("MyObject");
        Instantiate(prefab);
    }
}

 

  (3)LoadFromMemoryAsync:从内存加载,一般用于加密资源。

 

        //异步加载资源
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path1));
        yield 
return request;
        
//加载共同依赖资源,如贴图、材质
        AssetBundleCreateRequest request2 = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path2));
        yield 
return request2;
        AssetBundle ab = request.assetBundle;
        AssetBundle ab2 = request2.assetBundle;

        
//使用里面的资源
        GameObject wallPrefab1 = ab.LoadAsset("CubeWall");

        Instantiate(wallPrefab1);

        (4)UnityWebRequest

 

    首先是创建一个web request(调用UnityWebRequest.GetAssetBundle), 然后进行资源的获取(调用DownloadHandlerAssetBundle.GetContent)

StartCoroutine(InstantiateObject());

IEnumerator InstantiateObject()

    {
        string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;         UnityEngine.Networking.UnityWebRequest request =             UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
        yield return request.Send();
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject cube = bundle.LoadAsset("Cube");
        GameObject sprite = bundle.LoadAsset("Sprite");
        Instantiate(cube);
        Instantiate(sprite);
    }


  使用方式建议:
  (1)随包资源StreamingAssets:
    未压缩或LZ4压缩:LoadFromFile;
    LZMA压缩:可使用 WWW.LoadFromCacheOrDownload解压缩到本地磁盘。
  (2)热更新资源:LZMA+WWW.LoadFromCacheOrDownload+Caching.compressionEnabled;
  (3)加密资源:LZ4+LoadFromMemory;

 

  (4)自己压缩的资源:UncompressAssetBundle的AssetBundle包+自己的算法压缩+LoadFromFileAsync。

 

 

WWW.LoadFromCacheOrDownload会被UnityWebRequest取代

 

 

资源卸载
  AssetBundle.Unload(false):干掉压缩包,bundle不再可用,即不能再通过bundle.Load加载资源;
  AssetBundle.Unload(true):干掉压缩包,和所有从中加载(load)出来的资源。
  所以卸载资源一般有两种玩法:
  (1)AssetBundle.Unload(false)结合Resource.UnloadUnusedAssets()
  (2)碎片化使用AssetBundle.Unload(true)

  具体怎么用要结合游戏本身的数据特点来定制。关于要不要Unload释放AssetBundle本身的内存,也有两种主流玩法,一种是即用即卸(LoadAsset以后立马释放AssetBundle),一种是缓存AssetBundle不卸载,两种方法各有优劣,需结合使用。

 

 

unity在场景中的Object被移除的时候不自动释放objects,资源的清理需要再特定的时间触发(场景切换)或者手动的管理。所以怎么加载和卸载资源显得尤为重要,不合适的加载可能会导致资源的重复加载,不合适的卸载可能会带来资源的缺失(比如丢失贴图)。

  对于assetbundle的资源管理,最重要的是掌握什么时候调用AssetBundle.Unload(bool)这个函数,传入true/false会有不同的卸载策略。这个API会卸载对应的assetbundle的头部信息,参数对应着是否同时卸载从该assetbundle中实例化的所有Objects。

  AssetBundle.Unload(true)会卸载assetbundle中的所有gameobjects以及其依赖关系,但是并不包括基于其Objects实例化(复制)的Object(因为这些object不属于该assetbundle,只是引用),所以当卸载贴图相关的assetbundle的时候,场景中对其引用的实例化物体上会出现贴图丢失,也就是场景中会出现红色的区域,unity都会将其处理成贴图丢失。

  举例说明,假设材质M来自于assetbundle AB, 如果 AB.Unload(true), 那么场景中任何M的实例都会被卸载和销毁,如果AB.Unload(false), 那么就会切断材质M实例与AB之间的关系:

AssetBundle 资源打包 加载 卸载_第5张图片

  那么如果该assetbundle AB在后面再次被加载,unity不会重新关联其关系,这样在后续的使用中,就会出现一份材质的多个实例:

AssetBundle 资源打包 加载 卸载_第6张图片

  所以通常情况下,AssetBundle.Unload(false) 并不能带来较为合理的释放结果,AssetBundle.Unload(true)通常用来确保不会在内存中多次拷贝同一个资源,所以其更多的被项目所采纳,此外还有两个常用的方法用来确保其使用:

1)在游戏中,对于场景的卸载有明确的规划,比如在场景切换中或者场景加载中;

2)管理好对每个单独的object的计数,只有在没有引用的时候才卸载该assetbundle,这样可以规避加载和卸载过程中的多份内存拷贝问题。

  如果要使用AssetBundle.Unload(false), 那么这些实例化的对象可以通过2中途径卸载:

1)清除对不需要物体的所有引用,场景和代码中都需要清楚,然后调用Resources.UnloadUnusedAssets;

2) 在场景加载的时候采用非增量的方式加载,这会清楚当前场景中的所有Objects,然后反射自动调用Resources.UnloadUnusedAssets

如果你不想管理这些assetbundle,unity推出了AssetBundle Manager,可以学习了解一下,此外Unity还推出了一些AssetBundle Browser Tool, 也可以学习了解一下。

 

 

9 校验

 

CRC MD5 SHA1

相同点

CRC、MD5、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)领域,比如文件校验、数字签名等。

 

10 

Unity Asset Bundle Browser tool

 

 

 

 

 

美朝最新动态:美朝双方高级官员举行会谈  朝鲜表遗憾美方态度称其“强盗”

你可能感兴趣的:(打包,unity)