1. 程式人生 > >Unity 3D--外部載入資源AssetBundles

Unity 3D--外部載入資源AssetBundles

Unity 3D裡有兩種動態載入機制

     一是Resources.Load

     一是通過AssetBundle

     其實兩者本質上沒有什麼區別。Resources.Load就是從一個預設打程序序包裡的AssetBundle里加載資源,而一般AssetBundle檔案需要你自己建立,執行時動態載入,可以指定路徑和來源的。其實場景裡所有靜態的物件也有這麼一個載入過程,只是Unity後臺替你自動完成了。

1.    AssetBundles是什麼?

     在一些大型的網路遊戲,或者載入比較多的一些場景時,如果要等待所有模型,貼圖等各種資原始檔載入完畢才能執行遊戲,對使用者將會是一個很頭大的事情。所以就需要用到動態載入,即

AssetBundles。比如玩家在進入遊戲時先載入一些周圍的場景檔案,這樣不僅可以提高速度還可以減少記憶體資源的消耗。       

     AssetBundles是可以把unity3d中你所建立的檔案或任何資源匯出的一種檔案格式,這些檔案匯出後使用的是一種特定的檔案格式(.Unity3d),這些特定格式的檔案能在需要的時候載入到場景中。而這些特定的檔案格式可以是模型,貼圖,聲音檔案甚至是場景檔案,它們是先前就被設計好的檔案,所以很容易就可以被下載到你所建立的遊戲或場景中來

     AssetBundles 可以是任意型別的檔案只要是unity3d能識別的資原始檔格式,識別主要是以副檔名為準,比如

.prefab等等。當然如果你想包含自定義的二進位制檔案,需要命名這些檔案為以".bytes"為字尾,Unity將會把這些檔案導成TextAssets

2.    Creating AssetBundles 建立資源包

有三個類方法可以用來構建資源包:

  • BuildPipeline.BuildAssetBundle allows you to build AssetBundles of any type of asset.
        可以構建任意型別資源的資源包。【建立一個壓縮好的包含Assets下的所有資原始檔.unity3d。可以包含是專案目錄下的任意資源,而把所有的資源壓縮成一個.unity3d的檔案,這個檔案包括所有的預置物體(prefabs),紋理貼圖(textures),模型,動畫。使用AssetBundle.mainAsset這個函式可以很方便的讓你指定一個定義好的物體。被壓縮的資源儲存在pathName. Options,會自動的允許使用者包含相關的或者需要用到的】
  • BuildPipeline.BuildStreamedSceneAssetBundle is used when you want to include only scenes to be streamed and loaded as the data becomes available.
    用來當你希望只包括流場景,使資料載入變為可用。【建立一個或多個場景,這些場景所需要的所有資源將被壓縮入資源包,即asset bundle裡面。資源包中的場景檔案可以在任何平臺上建立,而且這些檔案往往是以一個單一的unity3d檔案格式被用來建立。使用WWW類可以下載場景檔案。當場景檔案被下載好可以使用WWW.LoadFromCacheOrDownload來載入下載好的場景檔案。】
  • BuildPipeline.BuildAssetBundleExplicitAssetNames is the same as BuildPipeline.BuildAssetBundle but has an extra parameter to specify a custom string identifier (name) for each object.
    BuildPipeline.BuildAssetBundle類似,但是有額外的引數來指定每個物體的自定義的字串(名字)。【建立一個自定義名字的資源包方法:建立一個包含所有資源的一個壓縮好的unity3d檔案。AssetBundle可以包括任何專案目錄下的資原始檔。在assetNames引數中提供一個與資源數目相同大小的字串陣列。在資源陣列中儲存的資訊與資原始檔名相同,可以傳遞AssetBundle.Load去載入一個指定的資源。使用BuildAssetBundle時,只需使用資源的路徑名。壓縮好的資源包檔案將會被儲存在pathName. Options,允許使用者自動包含與之相關的或者總是包含完整的資源去代替確切的參照物體。】

          當使用上面的三個函式做完準備工作,我們現在就需要去下載這些資源然後載入它們。

3.    Downloading AssetBundles 下載資源包

function Start ()
{
     var www = WWW.LoadFromCacheOrDownload ("http://myserver.com/myassetBundle.unity3d", 
5);
yield www;
if (www.error != null)
{
     Debug.Log (www.error);
     return;
}
    var myLoadedAssetBundle = www.assetBundle;
    var asset = myLoadedAssetBundle.mainAsset;
}

4.   Loading and unloading objects from an AssetBundle從資源包載入和解除安裝物件

        下載完以後,等於把硬碟或者網路的一個檔案讀到記憶體一個區域,這時候只是個AssetBundle記憶體映象資料塊,還沒有Assets的概念。就可以使用這三個不同的函式來載入物體了:

  • AssetBundle.Load會載入物體,使用該物體的名字作為識別的引數。名字可以在Unity3d中Project view看到。你可以自由選擇去傳遞物件變數的型別來確認該載入物件是否是被指定的型別。
  • AssetBundle.LoadAsync 與AssetBundle.Load 函式相類似,但是當資源載入時它不會阻礙主執行緒。如果同時要載入比較大的資源或者很多資源時,這個函式會比較有用,它可以避免程式的暫停,因為它會同步載入。
  • AssetBundle.LoadAll 顧名思義這個函式是用來載入所有在你資源包中的物件。作為AssetBundle.Load這個函式,你可以隨意用該物件的型別去過濾。

        使用AssetBundle.Unload這個函式可以解除安裝載入好的資源,這個函式有一個布林值的引數是用來告訴Unity是否要解除安裝所有的資料(包含載入的資源物件)或者只是已經下載過的被壓縮好的資源資料。如果要在資源包中從你的應用程式要使用一些物件或者你想釋放一些記憶體,可以傳遞false這個值來解除安裝已經壓縮好了的檔案從你的記憶體中(即.unity3d檔案)。如果要完全解除安裝所有的資源資料,需要傳遞true這個值,這將會銷燬所有的資源包器中載入的資源。

        AssetBundle.Unload(flase)是釋放AssetBundle檔案的記憶體映象,不包含Load建立的Asset記憶體物件。

        AssetBundle.Unload(true)是釋放那個AssetBundle檔案記憶體映象和並銷燬所有用Load建立的Asset記憶體物件。

5. Instantiating objects from AssetBundles 從資源包例項化物體

       下載了資源,也載入好了,那麼就該在場景中使用Instantiate函式去例項化它了。

        Instantiate一個Prefab,是一個對Assets進行Clone(複製)+引用結合的過程,GameObject transform 是Clone是新生成的。其他mesh / texture / material / shader 等,這其中些是純引用的關係的,包括:Texture和TerrainData,還有引用和複製同時存在的,包括:Mesh/material/PhysicMaterial。引用的Asset物件不會被複制,只是一個簡單的指標指向已經Load的Asset物件。

Unity裡每個Script都是一個封閉的Class定義而已,並沒有寫呼叫程式碼,光Class的定義指令碼是不會工作的。其實Unity引擎就是那個呼叫程式碼,Clone一個script asset等於new一個class例項,例項才會完成工作。把他掛到Unity主執行緒的呼叫鏈裡去,Class例項裡的OnUpdate OnStart等才會被執行。多個物體掛同一個指令碼,其實就是在多個物體上掛了那個指令碼類的多個例項而已,這樣就好理解了。在new class這個過程中,資料區是複製的,程式碼區是共享的,算是一種特殊的複製+引用關係。

        當你Destroy一個例項時,只是釋放那些Clone物件,並不會釋放引用物件和Clone的資料來源物件,Destroy並不知道是否還有別的object在引用那些物件。等到沒有任何遊戲場景物體在用這些Assets以後,這些assets就成了沒有引用的遊離資料塊了,是UnusedAssets了,這時候就可以通過Resources.UnloadUnusedAssets來釋放,Destroy不能完成這個任務,AssetBundle.Unload(false)也不行,AssetBundle.Unload(true)可以但不安全,除非你很清楚沒有任何物件在用這些Assets了。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d";
IEnumerator Start () {
    // Start a download of the given URL
	// 開始從指定路徑下載
    WWW www = WWW.LoadFromCacheOrDownload (url, 1);
    // Wait for download to complete
	// 等待下載完成
    yield return www;
    // Load and retrieve the AssetBundle
	// 載入並取回資源包
    AssetBundle bundle = www.assetBundle;
    // Load the TextAsset object
	// 載入文字資源物件
    GameObject go = bundle.Load("myGameObject", typeof(GameObject)) as GameObject;
    // Instantiate the GameObject
	// 例項化該物件
    Instantiate(go);
}

        Unity不提供自動的一個可以取回所有被下載資源的列表。所以需要我們在指令碼中要建立這些資源物件的資訊和它們的路徑以便我們去查詢。

6. Including scripts in AssetBundles 在資源包中包含指令碼

       資源包可以作為TextAssets包含指令碼但是不會實際執行程式碼。如果想要在資源包包含用來執行應用程式的程式碼,需要預先編譯,然後使用Mono Reflection class來載入(注意:Reflection在iOS平臺不可用)。可以在任何版本的C#IDE編輯器(如:Monodevelop, Visual Studio)或者使用mono/.net 文件編輯器。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d";
IEnumerator Start () {
    // Start a download of the given URL
    WWW www = WWW.LoadFromCacheOrDownload (url, 1);
    // Wait for download to complete
    yield return www;
    // Load and retrieve the AssetBundle
    AssetBundle bundle = www.assetBundle;
    // Load the TextAsset object
    TextAsset txt = bundle.Load("myBinaryAsText", typeof(TextAsset)) as TextAsset;
    // Load the assembly and get a type (class) from it
    var assembly = System.Reflection.Assembly.Load(txt.bytes);
    var type = assembly.GetType("MyClassDerivedFromMonoBehaviour");
    // Instantiate a GameObject and add a component with the loaded class
    GameObject go = new GameObject();
    go.AddComponent(type);
}

一個常見的錯誤:

         從某個AssetBundle裡Load了一個prefab並克隆之:obj = Instantiate (AssetBundle1.Load('MyPrefab”);

          這個prefab比如是個npc,然後你不需要他的時候你用了:Destroy(obj);你以為就釋放乾淨了。其實這時候只是釋放了Clone物件,通過Load載入的所有引用、非引用Assets物件全都靜靜靜的躺在記憶體裡。這種情況應該在Destroy以後用:AssetBundle1.Unload(true),徹底釋放乾淨。如果這個AssetBundle1是要反覆讀取的 不方便Unload,那可以在Destroy以後用:Resources.UnloadUnusedAssets()把所有和這個npc有關的Asset都銷燬。

          當然如果這個NPC也是要頻繁建立 銷燬的那就應該讓那些Assets呆在記憶體裡以加速遊戲體驗。由此可以解釋另一個之前有人提過的話題:為什麼第一次Instantiate一個Prefab的時候都會卡一下,因為在你第一次Instantiate之前,相應的Asset物件還沒有被建立,要載入系統內建的AssetBundle並建立Assets,第一次以後你雖然Destroy了,但Prefab的Assets物件都還在記憶體裡,所以就很快了。

資源載入和釋放例子:

從磁碟讀取一個1.unity3d檔案到記憶體並建立一個AssetBundle1物件

AssetBundle AssetBundle1 = AssetBundle.CreateFromFile("1.unity3d");

從AssetBundle1裡讀取並建立一個Texture Asset,把obj1的主貼圖指向它

obj1.renderer.material.mainTexture = AssetBundle1.Load("wall") as Texture;

把obj2的主貼圖也指向同一個Texture Asset

obj2.renderer.material.mainTexture =obj1.renderer.material.mainTexture;

Texture是引用物件,永遠不會有自動複製的情況出現(除非你真需要,用程式碼自己實現copy),只會是建立和新增引用

繼續:

AssetBundle1.Unload(true) 那obj1和obj2都變成黑的了,因為指向的Texture Asset沒了

如果:

AssetBundle1.Unload(false) 那obj1和obj2不變,只是AssetBundle1的記憶體映象釋放

繼續:

Destroy(obj1),//obj1被釋放,但並不會釋放剛才Load的Texture

如果這時候:

Resources.UnloadUnusedAssets();

不會有任何記憶體釋放 因為Texture asset還被obj2用著

如果:

Destroy(obj2)

obj2被釋放,但也不會釋放剛才Load的Texture

繼續:

Resources.UnloadUnusedAssets();

這時候剛才load的Texture Asset釋放了,因為沒有任何引用了

最後CG.Collect();

強制立即釋放記憶體。

如何載入一堆大圖片輪流顯示又不爆掉?

不考慮AssetBundle,直接用www讀圖片檔案的話等於是直接建立了一個Texture Asset。

TLlist<string> fileList;
int n=0;
IEnumerator OnClick()
{
WWW image = new www(fileList[n++]);
yield return image;
Texture tex = obj.mainTexture;
obj.mainTexture = image.texture;
 
n = (n>=fileList.Length-1)?0:n;
Resources.UnloadAsset(tex);
}

相關推薦

Unity 3D--外部載入資源AssetBundles

Unity 3D裡有兩種動態載入機制:      一是Resources.Load;      一是通過AssetBundle;      其實兩者本質上沒有什麼區別。Resources.Load就是從一個預設打程序序包裡的AssetBundle里加載資源,而一般Asset

Unity 3D 資源載入與釋放

版本:unity 5.4.1  語言:C# 海水先在這裡坑一會,看了裡面的演算法深深感到自己數學能力的不足,經過同學的推薦,我準備先看會《數值分析》閉關修煉一下。 至於我在看的實戰核心技術的第十章MVC設計框架,提供了一堆無用的程式碼,然後讓你去看他的課程,我就自己研究

Unity非同步載入和讀取外部圖片資源

後臺執行緒讀取本地或者雲端png\jpg圖片。 背景:做VR開發中,最經常用到的一個功能就是載入外部的全景圖,並且在頭盔裡顯示。但是一張4K的全景圖動輒10M左右的大小,而且需要佔用24M(4K 的jpg格式,一個畫素24bit-RGB)記憶體。如果在主執

寫一個unity載入資源管理器

需求: 1.能切換不同載入模式     開發階段編輯器執行直接載入資源無需打ab包     測試或正式釋出階段通過ab包載入資源 2.快取機制 能定時清理長時間未使用的資源記憶體 3.既有同步載入 也有非同步載入

Unity 3D 資源工作流程 Asset Workflow

  這裡我們講解Unity的單一資源的使用步驟,這些步驟是通用的且僅作為基本動作的概述,例如,我們將討論如何使用一個三維網格。 Create Rough Asset 建立粗糙資源 使用任何Unity所支援的3D建模軟體來建立一個粗製版資源,我們的例子將使用Maya,使用資源工作,直到你準備好儲

unity 通過xml外部載入視訊連結,圖片

載入xml的程式碼   using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using System.Xml; using

unity Editor自動生成材質及動態載入資源

最近這兩天在做一個專案,然後裡面有六十多個素材,還要全部生成材質球,差點人都廢了,然後去手冊上著了一下可以自動生成材質球的程式碼。然後自動生成材質球的過程中我還想要給材質球賦予一個預設的漫反射貼圖,貼圖是從網上下載來的,踩了數不清的坑之後終於搞定了。

unity動態載入資源

初學Unity的過程中,會發現打包釋出程式後,unity會自動將場景需要引用到的資源打包到安裝包裡,沒有到的不會跟進去。我們在編輯器裡看到的Asset中的檔案結構只是工作於編輯器環境下的,在遊戲中unity會重新組織資料庫。這是我們一定會遇到一個需求,即動態的載入我們自己的檔

Unity:非同步載入場景資源進度介面

建立載入介面LoadingScene,用於處理載入進度條。 匯入NGUI資源包,在Unity3D選單欄中選中NGUI-Open-Prefab Toolbar,在Prefab Toolbar視窗中,選中Control - Colored Progress Bar拖拽至Hier

Unity載入資源的3種方法

方法一: 在指令碼中public一個量,然後在編輯器把相應的prefab拖過來 這種方法靈活但也混亂 方法二: 動態載入,Assets目錄下建立一個名為Resources的資料夾,通過Resou

C# Unity用AssetBundle載入本地資源 (1)

/// <summary>     ///  AssetBundle載入器     /// </summary>     public class AssetBundleLoger     {         /// <summary>

Unity3d外部載入音訊,視訊,圖片等資源 及根據路徑獲取制定格式的檔案

using UnityEngine; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; public class SetPath : MonoBehavi

Unity動態載入資源-Resource.Load

unity中使用Resource.Load載入資源前提--Asset下存在Resources資料夾且要載入的資源在Resources目錄下; Resources.Load返回一個Object型別,因此在例項化時應進行型別轉換 當然也可以在載入時便進行型別轉換,這樣就可以避

Unity開發實戰探討-資源載入釋放最佳策略

注:本文中用到的大部分術語和函式都是Unity中比較基本的概念,所以本文只是直接引用,不再詳細解釋各種概念的具體內容,若要深入瞭解,請查閱相關資料。   Unity的資源陷阱 遊戲資源的載入和釋放導致的記憶體洩漏問題一直是Unity遊戲開發的一個黑洞。因此導致遊戲拖慢,卡頓甚至閃退問題成為了U

Unity開發實戰探討-資源載入釋放最佳策略簡要心得

Unity開發實戰探討-資源的載入釋放最佳策略簡要心得 看過我另外一篇關於Unity資源釋放隨筆《Unity開發實戰探討-資源的載入釋放最佳策略》如果覺得略微複雜,那麼下面是一些比較簡要的心得體會: 概括 常用資源載入的方法有三種:靜態,Resources內部資源,AssetBundle外部資源 資源

Unity 3D】學習筆記三十:遊戲元素——遊戲地形

nbsp 3d遊戲 strong 直觀 分辨率 == 摩擦力 fill 世界 遊戲地形 在遊戲的世界中,必然會有非常多豐富多彩的遊戲元素融合當中。它們種類繁多。作用也不大同樣。一般對於遊戲元素可分為兩種:經經常使用。不經經常使用。經常使用的元素是遊戲中比較重要的元素。一

Unity 3D】學習筆記四十二:粒子特效

空間 獲得 material package 一個 log 創建 spa mpi 粒子特效 粒子特效的原理是將若幹粒子無規則的組合在一起。來模擬火焰,爆炸。水滴,霧氣等效果。要使用粒子特效首先要創建,在hierarchy視圖中點擊create——particle s

再議Unity 3D

body 接納 ng- ebo unity3d遊戲 復雜 位數 市場 現實 一年前,偶發沖動,翻譯了《[譯] Unity3D遊戲和facebook綁定(1:簡單介紹)》系列文章。 如今看有2個明顯的優點, 一:給這個不溫不火的博客帶了top 3的人氣; 二:我個

Unity 3D Time 類

時間 one nbsp ren returns article atime .html ots Time class in UnityEngine Description The interface to get time information from Unity

unity的animation動畫資源壓縮

objects key oot tostring llc bindings engine edit com 最近更新了一批骨骼動畫資源,不看不知道,一看嚇一跳,之前優化掉的內容還需要重新處理一遍,因此。。現在就先把之前的東西拿出來做個記錄。 所幸之前對動畫有做動態加載,現在