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演算法,一旦它被下載了之後,它會使用
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包資源目錄:
StreamingAssets:一個AssetBundle包,內含AssetBundleManifest型別的Asset,記錄了所有bundle包及相互間的依賴關係。
執行時需要首先載入這個AssetBundleManifest,然後根據其提供的depence資訊載入依賴的bundle包。
StreamingAssets.manifest:全域性manifest,全域性manifest的名字和打包生成的目錄同名,不是固定的,這裡是生成在StreamingAssets目錄下。
Cube.assetbundle:資源bundle。
Cube.assetbundle.manifest:每個資源自己的manifest,與bundle一一對應,只是用來做增量build,執行時根本不需要。
^_^場景打包成AssetBundle資源和普通資源打包有所區別。
這是一個普通的assetbundle
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檔案裡面定義了使用的資源和依賴:
載入Manifests檔案可以處理資源的依賴
AssetBundleassetBundle = 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和不壓縮資源一樣,都可以不解壓,而直接讀取包中的資源的。
7 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.<GameObject>("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<GameObject>("Cube"); GameObject sprite = bundle.LoadAsset<GameObject>("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取代
8 資源解除安裝
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 AB在後面再次被載入,unity不會重新關聯其關係,這樣在後續的使用中,就會出現一份材質的多個例項:
所以通常情況下,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