Related Posts Plugin for WordPress, Blogger...

6-30 AssetBundle Option And Manifest File

本章要來介紹AssetBundle的打包選項,官方的詳細文檔可參考如下網址:
https://docs.unity3d.com/Manual/AssetBundles-Building.html

不過同樣要來替大家解釋一下各種打包效果如何。首先從程式碼看,BuildAssetBundleOptions在如下用紅色框起來的地方進行設定。

BuildAssetBundleOptions.None:使用LZMA算法壓縮,壓縮的包更小,但是加載時間更長。使用之前需要全部解壓縮,解壓縮完畢以後會自動使用LZ4算法重新壓縮並儲存到本地端,所以使用資源的時候不需要全部解壓縮。

BuildAssetBundleOptions.UncompressedAssetBundle:不壓縮,容量大,但加載時間最快。

BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4算法壓縮,容量比LZMA壓縮後還大,但好處是使用資源時不用全部解壓縮,只要解壓縮所需的『Chunk』部分即可,因此又被稱為Chunk-Based演算法。

如果使用LZ4算法壓縮,加載速度與不加縮的方法一樣快,但容量比不壓縮還小。

以下實際幫大家檢驗看看。
使用BuildAssetBundleOptions.None

使用BuildAssetBundleOptions.ChunkBasedCompression

使用BuildAssetBundleOptions.UncompressedAssetBundle

上述三種只是Unity官方文檔介紹的基礎選項,實際上在BuildAssetBundleOptions內還有更多的選項,大家可以從以下網址查看更詳細的內容:
https://docs.unity3d.com/ScriptReference/BuildAssetBundleOptions.html

下列我幫大家針對官方的說明進行翻譯,但不會有實例示範。
DisableWriteTypeTree
將使AssetBundle易受腳本或Unity版本更改的影響,但文件更小,加載速度更快。此標誌僅影響默認包含類型信息的平台的AssetBundles。 例如,Web平台必須存在類型信息,如果在構建BuildTarget.WebPlayer時指定此標誌,Unity將拒絕構建AssetBundle。

DeterministicAssetBundle
在重建AssetBundle時,保證重建後的物件具有相同的ID。 由於它是一個32位元的Hash儲存空間,如果AssetBundle中有很多物件,將會增加Hash衝突的可能性。 在這種情況下,Unity會給出錯誤並且不會構建AssetBundle。 Hash基於Asset的GUID和Asset中物件的本地ID。 DeterministicAssetBundle的加載速度也比普通的AssetBundle要慢,這是因為執行緒化的背景加載API通常期望物件是有序排列的,可以減少搜尋時間,但使用DeterministicAssetBundles後不可能是有序排列。

ForceRebuildAssetBundle
允許重新構建AssetBundle,即使沒有修改任何Asset

IgnoreTypeTreeChanges
可以在執行增量構建檢查時忽略TypeTree的更改。通過設置此標誌,如果包含的資產沒有更改,但TypeTree更改,則不會重建AssetBundle。

AppendHashToAssetBundleName
將Hash追加到AssetBundle的名稱。

StrictMode
如果有任何錯誤報告,則不要讓構建成功。如果沒有這個標誌,那麼非致命錯誤(例如未能編譯特定平台的Shader)不會導致構建失敗,但可能會導致運行時的錯誤行為。

DryRunBuild
為AssetBundles執行空運行構建,但不實際構建它們。啟用此選項後,BuildPipeline.BuildAssetBundles仍會返回一個AssetBundleManifest對象,其中包含有效的AssetBundle依賴項目和Hash。

DisableLoadAssetByFileName
AssetBundles默認有三種查找同一資產的方式:完整Asset路徑Asset文件名和帶擴展名的Asset文件名。 Asset的完整路徑經過序列化後存入AssetBundles中,加載AssetBundles時再自動生成帶擴展名的文件名和文件名。

例如:“Assets / Prefabs / Player.prefab”,“Player”和“Player.prefab”


此選項將在AssetBundles上設置一個標記,以防止使用Asset文件名進行查找。 此選項可以節省運行時的記憶體以及讀取效能


DisableLoadAssetByFileNameWithExtension
與上一個選項類似,防止使用帶擴展名的Asset文件名進行查找。

The Manifest File

For every bundle generated, including the additional Manifest Bundle, an associated manifest file is generated. The manifest file can be opened with any text editor and contains information such as the cyclic redundancy check (CRC) data and dependency data for the bundle. 

對於生成的每個包(包括附加的Manifest包),都會生成關聯的清單文件。 清單文件可以用任何文本編輯器打開,並包含諸如循環冗餘校驗(CRC)數據和依賴性數據等信息。打開來的模樣應會如下圖。

Manifest文件是以YAML格式儲存,可以從Assets欄位看見該AssetBundle內部儲存了哪些資源。Dependencies則會顯示是否有依賴其他的AssetBundle。如下圖是另外一個AssetBundle的Manifest文件,於Dependencies中便標明了依賴的對象。

Manifest文件主要是給Unity進行AssetBundle更新的時候使用,以下針對各項欄位數據進行說明
  • CRC:循環冗餘校驗
  • AssetFileHash:AssetBundle中所有資產文件的Hash,只用來做增量建立時的檢查。
  • TypeTreeHash:AssetBundle中所有類型的Hash,只用來做增量建立時的檢查。
  • ClassTypes:AssetBundle中包含的所有類型,這些數據用來得到一個新的單獨的Hash。當typetree做增量構建檢測。
  • Assets:所有在AssetBundle中的資產的名稱。
  • Dependencies:AssetBundle所依賴的其它AssetBundle的名字
  • 這個清單文件只是用來做增量構建的,非運行時必須。

Dependencies還有一個作用,就是當AssetBundle因分組策略的關係,將部分『共享的資源』另外打包成一個AssetBundle,這時就需要載入這個有Dependencies的AssetBundle。從AssetBundle.manifest文件可以看見所有AssetBundle與Dependencies。

文件中可見building_a.neko與building_b.neko的Dependency為share.neko。如不懂分組策略,可以先看看以前的文章:
6-29 Asset Assignment Strategies

假如我們只載入building_a.neko中的模型的話,就會出現如下圖的情況,由於房子的Texture放在share.neko中,導致模型看起來很奇怪。

我們可以透過下列程式碼讀取AssetBundleManifest,並從中判斷building_a.neko的Dependencies,藉此可以讀取『共享資源』的AssetBundle。

讀取完以後的房子模型就正常啦!

本次更新的程式碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class LoadAssetBundle : MonoBehaviour {

 [SerializeField] string loadPath;
 [SerializeField] string assetName;
 [SerializeField] Transform assetTransform;

 void Start () {
  LoadFromFile ();
  LoadAssetManifestAndDependencies();
 }

 // 載入AssetManifest並讀取依賴的AssetBundle
 void LoadAssetManifestAndDependencies(){
  // 載入AssetManifest文件
  AssetBundle manifestBundle = AssetBundle.LoadFromFile ("AssetBundle/AssetBundle");
  AssetBundleManifest manifest = 
   manifestBundle.LoadAsset ("AssetBundleManifest");

  // 取得特定AssetBundle的Dependencies
  string[] dependencies = manifest.GetAllDependencies("scene/building_a.neko");
  foreach (string assetBundleName in dependencies) {
   // 根據Dependencies載入相依賴的其他AssetBundles
   AssetBundle.LoadFromFile (Path.Combine("AssetBundle", assetBundleName));
  }
 }

 void LoadFromFile(){
  // 加載AssetBundle
  AssetBundle assetBundle = AssetBundle.LoadFromFile(loadPath);
  // 從AssetBundle取得想要的資源
  GameObject Building_a = assetBundle.LoadAsset(assetName);
  // 產生資源
  Instantiate(Building_a, assetTransform.position, assetTransform.rotation);
 }

 
}


留言