AssetBundle使用心得【資源加載】


0.資源加載方式

  1. 靜態資源 Asset下所有資源稱為靜態資源
  2. Resources資源 Resources目錄下,通過實例化得到的資源
  3. AssetBundle資源 又稱為增量更新資源

1.什么是AssetBundle包(下面稱為AB包)

  一種存放在硬盤上壓縮文件組形式,包含序列化文件(Manifest)與資源文件(Resources)。壓縮包的壓縮算法包括LZMA(流式壓縮)與LZ4(塊壓縮)算法,前者壓縮比例更高解壓耗時更大。

  PS:www使用后是需要銷毀的!!!www.Dispose();

2.AB包打包原則有哪些

  • 引用同意貼圖、材質、模型的資源最好一起打包
  • 一起展示的部分最好一起打包,比如一個場景,一個面板等
  • 導出目錄一定要存在,不存在導出會失敗
  • 加載資源時請務必清空一次緩存區!!重要!重要!

3.AB場景資源打包

  • 打包前把需要的shader放到Edit/ProjectSetting/Graphics 的Always Includes Shaders上,不然加載后會出現shader關聯不上的問題

方式1.場景打包方式0 (打成多個資源包)


 

  • 設置要打包的場景資源

  • Editor中導入如下代碼
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;

public class ABSceneAll 
{
    [MenuItem("Custom Editor/Version1CreateAB")]
    static void CreateSceneVersion1()
    {
        //清空一下緩存
        Caching.CleanCache();

        //路徑
        string outPath = Application.streamingAssetsPath + "/AssetBundle";
        if (!Directory.Exists(outPath))
        {
            Directory.CreateDirectory(outPath);
        }

        //檢測所有的AB包資源創建Manifest文件 這里選擇的是不進行任何特殊要求
        AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(outPath, BuildAssetBundleOptions.None, BuildTarget.Android);

        //存儲txt文件
        if (manifest != null)
        {
            string txtPath = Application.streamingAssetsPath + "/AssetBundle" + "/gamehall.txt";
            string manifestPath = Application.streamingAssetsPath + "/AssetBundle" + "/AssetBundle.assetbundle";
            string temp = "";

            //得到所有的需要打AB包的資源名 
            string[] assetBundleNames = manifest.GetAllAssetBundles();

            //提示信息 & 安全校驗
            if (assetBundleNames.Length != 2)
            {
                EditorUtility.DisplayDialog("錯誤提示", "這是個安全校驗,表示已經出問題了打包的場景過多", "確定");
                return;
            }
            
            for (int i = 0; i < assetBundleNames.Length; i++)
            {
                temp += assetBundleNames[i] + "" + manifest.GetAssetBundleHash(assetBundleNames[i]).ToString() + "\r\n";
            }
            temp += "前二十位:" + manifest.GetAssetBundleHash(assetBundleNames[1]).ToString().Substring(0, 10) + manifest.GetAssetBundleHash(assetBundleNames[0]).ToString().Substring(0, 10);

            FileStream fs = new FileStream(txtPath, FileMode.OpenOrCreate, FileAccess.Write);//創建寫入文件 
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine(temp);//開始寫入值
            sw.Close();
            fs.Close();
        }
        

        //資源刷新
        AssetDatabase.Refresh();
    }
}
View Code
  • Custom Editor中選擇對應選項進行打包(這里打出來的包就包含了Manifest文件,2個不同的AB文件)
  • 讀取方式如下代碼

 

/***************************************
Editor: Tason
Version: v1.0
Last Edit Date: 2018-XX-XX 
Tel: 328791554@qq.com
Function Doc: 

***************************************/

using UnityEngine;
using System.Collections;


public class MyTest : MonoBehaviour 
{
    void Awake()
    {

        StartCoroutine(LoadScene());
    }

    private IEnumerator LoadScene()
    {
        Caching.CleanCache();
        //加載多個文件 Manifest + AssetBundle資源
        WWW downManifest = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + "/AssetBundle", 1);
        //加載時間 600 * 0.1s 最長加載60s
        for (int i = 0; i < 600; i++)
        {
            if (downManifest.isDone)
            {
                break;
            }
            if (i % 3 == 0)
                Debug.Log("加載進度:" + downManifest.progress.ToString("#0.00"));
            yield return new WaitForSeconds(0.1f);
        }
        if (downManifest.isDone)
            Debug.Log("文件目錄加載成功 ----- √");
        else
        { 
            Debug.Log("文件目錄加載失敗 ----- X");
            yield break;
        }

        AssetBundleManifest abm = downManifest.assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        string[] abResourcesNames = abm.GetAllAssetBundles();
        for (int i = 0; i < abResourcesNames.Length; ++i)
        {
            WWW downResource = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + '/' + abResourcesNames[i], 1);
            for (int n = 0; n < 600; n++)
            {
                if (downResource.isDone)
                {
                    break;
                }
                if (i % 3 == 0)
                    Debug.Log("加載進度:" + downManifest.progress.ToString("#0.00"));
                yield return new WaitForSeconds(0.1f);
            }
            if (downResource.isDone)
                Debug.Log(string.Format("文件[{0}]加載成功 ----- √", i));
            else
            {
                Debug.Log(string.Format("文件[{0}]加載失敗 ----- X", i));
                yield break;
            }
            
        }

        Application.LoadLevel("S1");

        yield return null;
        
    }
}
View Code

 

 

 

方式2.場景打包方式1(打成1個資源包)


 

  • 設置要打包的場景資源

 

  • Editor中導入如下代碼
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;

public class ABSceneAll 
{
    [MenuItem("Custom Editor/Version0CreateAB")]
    static void CreateSceneVersion0()
    {
        //清空一下緩存
        Caching.CleanCache();

        //路徑
        string outPath = Application.streamingAssetsPath + "/AssetBundle";
        if (!Directory.Exists(outPath))
        {
            Directory.CreateDirectory(outPath);
        }
        
        string TtargetPath = outPath + "/MY01.AB";
        string[] Scenes = { "Assets/Scene/S0.unity","Assets/Scene/S1.unity" };

        //打包場景
        BuildPipeline.BuildPlayer(Scenes, TtargetPath, BuildTarget.Android, BuildOptions.BuildAdditionalStreamedScenes);

        //資源刷新
        AssetDatabase.Refresh();
    }
}
View Code
  • Custom Editor中選擇第一個選項進行打包(這里打出來的包就是一個AB文件)
  • 讀取方式如下代碼
/***************************************
Editor: Tason
Version: v1.0
Last Edit Date: 2018-XX-XX 
Tel: 328791554@qq.com
Function Doc: 

***************************************/

using UnityEngine;
using System.Collections;


public class MyTest : MonoBehaviour 
{
    void Awake()
    {

        StartCoroutine(LoadScene());
    }

    private IEnumerator LoadScene()
    {
        Caching.CleanCache();
        //資源加載 對應單一資源
        WWW download = WWW.LoadFromCacheOrDownload("file://" + Application.streamingAssetsPath + "/AssetBundle" + "/MY01.AB", 1);
        yield return download;
        Application.LoadLevel("S1");
        download.Dispose();

        yield return null;
        
    }
}
View Code

 

AB包卸載


 

1.減少內存消耗

2.可能導致丟失的情況

AssetBundle.Unload(bool _b); ----- 這里不是靜態函數,前面要寫獲得的AB包對象 

True: 強制卸載,不管有沒有引用

False:卸載沒有用的資源

踩坑


  1. AssetBunlde不區分大小寫 所以建議全部用小寫
  2. Resources和AssetBundle路徑不同,Resources是相對路徑,AssetBundle都有
  3. 依賴關系一定要處理好,不然包體會很大
  4. AssetBundle.CreateFromFile不能加載壓縮過的AssetBundle,需要用www加載?!
  5. 資源間的關系必須是強關聯,不能有資源通過代碼里面的“Resources.Load<Type>”“Shader.Find”等弱關聯連接,因為它不會被打包進AB包(已測試,非常關鍵)
  6. 如果你要把資源包放在StreamingAssets目錄下進行資源加載,注意三端的路徑是不一樣的(這就很虛浮!)

    

#if UNITY_EDITOR || UNITY_STANDALONE_WIN
        string finalPath = "file://" + Application.dataPath + "/StreamingAssets";
#elif UNITY_ANDROID
        string finalPath = "jar:file://" + Application.dataPath + "!/assets";
#elif UNITY_IPHONE
        string finalPath = Application.dataPath + "/Raw"
#endif

  

Shader&AB包的關系!


 1.首先場景中關聯了材質的shader是會被打包到AB包中的(如果沒打包進去,就去菜單欄 Edit -----> ProjectSetting ----> Graphics -----> Always Included Shaders 中進行添加)

  EG:后面我又做了個實驗,通過AssetBundleBrower檢查過一次,發現確實打包進去了,但UITexture的Shader還是存在問題,使用上需要格外小心,最好還是給引用的地方放一份Shader,ε=(´ο`*)))很是無奈啊!!!!

 

 2.但是存在一些問題,比如加載AB的場景可能會存在“關聯丟失”的問題,表現出來的方式就像是shader沒有被打包,但是當你重新點選同樣的shader后又恢復了!這就很坑爹,原因不明

 3.那么如何解決這個問題呢,我參考了網上的一個方法,測試成功表示可行,在需要掛在新shader的父物體下面加上如下腳本即可,相當於它幫你記錄了關聯,然后運行時重新關聯了一次!(適用於Mesh UGUI)

 4.當然如果你的代碼里面存在創建模型這種騷操作,上訴掛載的方式是肯定行不通的,那就需要你自己加一句代碼來重新關聯咯,如:“m_materials[0].shader = Shader.Find("Custom/CutLineShader");”

/***************************************
Editor: Tason
Last Edit Date: 2018-XX-XX 
Tel: 328791554@qq.com
Function Doc: 
在需要自定義的使用自定義shader的物體的最上層父物體上加上這個
腳本可以保證shader關聯不丟失
Version: 0.0.1 測試版
***************************************/

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ShaderBD : MonoBehaviour 
{
    private List<Material> thisMaterial;
    private List<string> shaders;

    void Start()
    {
        thisMaterial = new List<Material>(6);
        shaders = new List<string>(6);

        MeshRenderer[] meshRenderer = GetComponentsInChildren<MeshRenderer>();
        int length = meshRenderer.Length;

        for (int i = 0; i < length; i++)
        {
            int count = meshRenderer[i].materials.Length;
            for (int j = 0; j < count; j++)
            {
                Material _mater = meshRenderer[i].materials[j];
                thisMaterial.Add(_mater);
                shaders.Add(_mater.shader.name);
            }
        }

        SkinnedMeshRenderer[] meshSkinRenderer = GetComponentsInChildren<SkinnedMeshRenderer>();
        length = meshSkinRenderer.Length;

        for (int i = 0; i < length; i++)
        {
            int count = meshSkinRenderer[i].materials.Length;
            for (int j = 0; j < count; j++)
            {
                Material _mater = meshSkinRenderer[i].materials[j];
                thisMaterial.Add(_mater);
                shaders.Add(_mater.shader.name);
            }
        }


        for (int i = 0; i < thisMaterial.Count; i++)
        {
            thisMaterial[i].shader = Shader.Find(shaders[i]);
        }
    }
}
View Code

 總結:如果需要使用AB包進行場景打包,那么NGUI上使用的Shader,需要單獨放在整合包(ABLoad的項目)中,如果是UGUI或者Mesh使用Shader,請在父物體上掛載上述腳本進行關聯!!!!后續持續關注

對了!下面是AssetBundleBrower(查看打包內容的UnityEditor 工具,直接導入Editor,在Window窗口中就能找到它了!支持5.6以上版本)

鏈接:https://pan.baidu.com/s/1BN2EofgVXIthKiAIq3JPyg 密碼:mg8i


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM