1. 程式人生 > >Unity AssetBundle 從入門到掌握(適合初學者)

Unity AssetBundle 從入門到掌握(適合初學者)

AssetBundle從入門到掌握

文章目錄

1. AssetBundle的定義和作用

  1. AssetBundle(簡稱AB包)是一個資源壓縮包,包含模型、貼圖、預製體、聲音、甚至整個場景,可以在遊戲執行的時候被載入;
  2. AssetBundle自身儲存著互相的依賴關係;
  3. 壓縮包可以使用LZMA和LZ4壓縮演算法,減少包大小,更快的進行網路傳輸;
  4. 把一些可以下載內容放在AssetBundle裡面,可以減少安裝包的大小;

2. 什麼是AssetBundle?

  1. 它是一個存在於硬碟上的檔案。可以稱之為壓縮包。這個壓縮包可以認為是一個資料夾,裡面包含了多個檔案。這些檔案可以分為兩類:serialized file 和 resource files。(序列化檔案和原始檔)
    serialized file:資源被打碎放在一個物件中,最後統一被寫進一個單獨的檔案(只有一個)
    resource files:某些二進位制資源(圖片、聲音)被單獨儲存,方便快速載入,可以Editor上讀取,方便檢視
  2. 它是一個AssetBundle物件,我們可以通過程式碼從一個特定的壓縮包加載出來的物件。這個物件包含了所有我們當初新增到這個壓縮包裡面的內容,我們可以通過這個物件加載出來使用。

3. AssetBundle使用步驟

流程

  1. 指定資源的AssetBundle屬性
    (xxxa/xxx)這裡xxxa會生成目錄,名字為xxx。’/'可以用於目錄劃分,Remove UnUsed name 可以移除沒有使用的屬性名
    指定資源的AssetBundle屬性
  2. 構建AssetBundle包
  3. 上傳AB包
  4. 載入AB包和包裡面的資源

4. 程式碼打包AssetBundle

使用編輯器擴充套件方法,將打包按鈕Build AssetBundles放於Asset選單下

using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string dir = "AssetBundles";
        if (Directory.Exists(dir) == false)
        {
            Directory.CreateDirectory(dir);
        }
        //BuildTarget 選擇build出來的AB包要使用的平臺
        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

壓縮方式

  1. Build的路徑(隨意只要是在硬碟上都可以的)
  2. BuildAssetBundleOptions
    BuildAssetBundleOptions.None:使用LZMA演算法壓縮,壓縮的包更小,但是載入時間更長。使用之前需要整體解壓。一旦被解壓,這個包會使用LZ4重新壓縮。使用資源的時候不需要整體解壓。在下載的時候可以使用LZMA演算法,一旦它被下載了之後,它會使用LZ4演算法儲存到本地上。
    BuildAssetBundleOptions.UncompressedAssetBundle:不壓縮,包大,載入快
    BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4壓縮,壓縮率沒有LZMA高,但是我們可以載入指定資源而不用解壓全部。
    注意:使用LZ4壓縮,可以獲得可以跟不壓縮想媲美的載入速度,而且比不壓縮檔案要小。

依賴打包
將需要同時載入的資源放在同一個包裡,各個包之間會儲存相互依賴的資訊
依賴打包

5. AssetBundle的載入和解除安裝

AB的載入

在開發階段將AB包放在本地,開發結束後再上傳到伺服器

public class LoadFromLocal : MonoBehaviour
{
    private void Start()
    {
        AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/scene/wall.jy");
        GameObject obj = ab.LoadAsset<GameObject>("wall");
        Instantiate(obj);
    }
}
private void Start()
{
    AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes("AssetBundles/scene/cube.jy"));
    GameObject obj = ab.LoadAsset<GameObject>("Cube(Clone)");
    Instantiate(obj);
}
IEnumerator Start()
{
    AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes("AssetBundles/scene/cube.jy"));
    yield return request;
    AssetBundle ab = request.assetBundle;
    GameObject obj = ab.LoadAsset<GameObject>("Cube(Clone)");
    Instantiate(obj);
}
 IEnumerator Start()
{
    while (Caching.ready == false)
    {
        yield return null;
    }

    WWW www = WWW.LoadFromCacheOrDownload(@"file://E:\U3D-Projects\Test2017.2.0\AssetBundles\scene\cube.jy", 1);
    yield return www;
    if (!string.IsNullOrEmpty(www.error))
    {
        Debug.Log(www.error);
        yield break;
    }
    AssetBundle ab = www.assetBundle;
    GameObject obj = ab.LoadAsset<GameObject>("Cube(Clone)");
    Instantiate(obj);
}
 IEnumerator Start()
{
    string url = @"file:///E:\U3D-Projects\Test2017.2.0\AssetBundles\scene\cube.jy";
    UnityWebRequest request = UnityWebRequest.GetAssetBundle(url);
    yield return request.SendWebRequest();
    //方式一
    //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
    //方式二
    AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
    GameObject obj = ab.LoadAsset<GameObject>("Cube(Clone)");
    Instantiate(obj);
}

AB載入方式:

  1. AssetBundle.LoadFromFile 從本地載入
  2. AssetBundle.LoadFromMemory 從記憶體載入
  3. WWW.LoadFromCacheOrDownload 下載後放在快取中備用(該方法逐漸被棄用)
  4. UnityWebRequest 從伺服器下載

從AB中載入資源:

  1. AssetBundle.LoadAsset(assetName)
  2. AssetBundle.LoadAllAssets() 載入AB包中所有的物件,不包含依賴的包
  3. AssetBundle.LoadAssetAsync() 非同步載入,載入較大資源的時候
  4. AssetBundle.LoadAllAssetsAsync() 非同步載入全部資源
  5. AssetBundle.LoadAssetWithSubAssets 載入資源及其子資源

AB的解除安裝

  1. 減少記憶體的使用
  2. 有可能導致丟失
  3. 在切換場景,或者確定不使用的時候解除安裝
    AssetBundle.Unload(true) 解除安裝所有資源,包含其中正被使用的資源
    AssetBundle.Unload(false) 解除安裝所有沒被使用的資源
    Resources.UnloadUnusedAssets 解除安裝個別未使用的資源

6. AssetBundle分組策略總結

邏輯實體分組

  • 一個UI介面或者所有UI介面一個包(這個介面裡面的貼圖和佈局資訊一個包)
  • 一個角色或者所有角色一個包(這個角色裡面的模型和動畫一個包)
  • 所有的場景所共享的部分一個包(包括貼圖和模型)
  1. 按照型別分組
    所有聲音資源打成一個包,所有shader打成一個包,所有模型打成一個包,所有材質打成一個包
  2. 按照使用分組
    把在某一時間內使用的所有資源打成一個包。可以按照關卡分,一個關卡所需要的所有資源包括角色、貼圖、聲音等打成一個包。也可以按照場景分,一個場景所需要的資源一個包

注意

  1. 經常更新的資源放在一個單獨的包裡面,跟不經常更新的包分離
  2. 把需要同時載入的資源放在一個包裡面
  3. 可以把其他包共享的資源放在一個單獨的包裡面
  4. 把一些需要同時載入的小資源打包成一個包
  5. 如果對於一個同一個資源有兩個版本,可以考慮通過後綴來區分,例如v1、v2、v3

7. Manifest檔案

什麼是Manifest檔案

Manifest檔案
crc為校驗碼,通過其檢查是否完整
Assets 表示包裡包含多少資源
Dependencies 表示包有哪些依賴
注意:在載入這些包之前,也需要載入依賴的包,不然會丟失這部分內容,顯示效果不正確

通過Manifest檔案得到某個包的依賴

包的依賴
可以注意到scene/cube.jy依賴於material.jy,而material.jy依賴於texture.jy

AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//GetAllDependencies獲取到所有的依賴物件
string[] strs = manifest.GetAllDependencies("scene/cube.jy");
//將所有依賴物件依次加載出來
foreach (var item in strs)
{
    Debug.Log(item);  
    AssetBundle.LoadFromFile("AssetBundles/" + item);
}

Console

如此,物件的材質也載入顯示出來:
載入顯示

8. 檔案校驗

CRC、MD5、SHA1都是通過對資料進行計算,來生成一個校驗值,該校驗值用來校驗資料的完整性。
CRC一般用於通訊資料的校驗,MD5和SHA1用於安全領域,例如檔案校驗,密碼加密等

9. AssetBundles瀏覽工具

GitHub下載地址

工具面板如下:
工具面板
工具面板

Build Target 用於設定AB包的目標平臺

OutPut Path 設定AB的輸出路徑

Build 一鍵打包