Unity 5 AssetBundle 基礎

前言一直以來,Unity 的 AssetBundle 機制與不透明的資訊一直為人所詬病(社群論壇有些批評,例如 asset 序列化管理架構、機制本身就不良,來源就不附上了),以往大部分的資訊都只是瞎子摸象試出來的結果,大都未經 Unity 官方證實。直到 Unity 4、5 開始,特別是從 Unity 5.x 開始,官方才比較願意公開詳細地說明 Unity AssetBundle、檔案資源系統及 Resources 機制。包括我在內,相信有不少 Unity 開發人員踩了不少 AssetBundle 相關的地雷,因此寫了這篇來記錄 AssetBundle 相關的基礎知識與細節。這篇主要是以 Unity 官方的 AssetBundle fundamentals 主題文章為主,加上一些自身開發經歷與參考。AssetBundle 概觀AssetBundle 是一款 Unity 的檔案資源系統,目的是為了讓資料交付可以相容於 Unity 自身的序列化系統。因為 Unity 本身的檔案資源處理機制,導致沒辦法直接使用檔案,原始 asset 檔與 Unity 最終在使用的 asset 是不同的。次要目的是縮減最終發布的 asset 大小,縮減執行期記憶體用量,可根據目標裝置給予最適合的內容(例如根據不同裝置選擇貼圖壓縮格式)等。AssetBundle 內部儲存結構一包 AssetBundle 由兩個部分組成。檔頭 (header)資料段 (data segment)AssetBundle Header檔頭由 Unity 在建置 AssetBundle 時產生,記錄了這包 AssetBundle 的 ID、壓縮格式、manifest 等資訊。Header Manifest這裡的 manifest 是指檔頭的 manifest,不是指 AssetBundle 建置出來的 manifest。Manifest 是一張查找表,以 UnityEngine.Object 名稱為主鍵,值為此 UnityEngine.Object 指向資料段的索引。官方指出大部分的平台都是用 C++ STL std::multimap 來實作,因此一個 UnityEngine.Object 可能會有很多個資料段。官方也說明演算法會根據不同平台來選擇以利最佳化,大都是使用各種平衡搜尋樹 (balanced search tree)。例如在 Windows、OSX 及 iOS 會採用紅黑樹 (red-black tree)。因此在建構 manifest 時,消耗的時間不是線性,會比線性還久。AssetBundle Data SegmentAssetBundle 資料段保存了 Unity 序列化 asset 後的原始資料。若資料段是被壓縮的,則會根據壓縮演算法來選擇要如何解壓縮這些資料段。例如 LZMA 壓縮會蒐集所有的資料段後才解壓縮,這代表了 LZMA 得解壓縮一整包 AssetBundle 才能取出裡面的 UnityEngine.Object,即便你只是想要取出某一個 UnityEngine.Object。而 Unity 5.3 之後新增的 LZ4 則是個別壓縮 UnityEngine.Object,允許獨立解壓縮取出一個,不用解壓縮一整包才能取出 UnityEngine.Object。     繼續閱讀
XenStalker's avatar
XenStalker 6月 21, 2017

Unity Resources 系統的最佳實務做法

Resources 的最佳做法別用 Resources別用 Resources別用 Resources因為很重要,所以要講三次。為什麼呢?理由有三。細粒度的記憶體控管會更困難。不當使用 Resources 資料夾會導致 app 啟動時間、建置時間更久。這問題在 Resources 檔案愈多,愈是明顯,尤其是規格比較差的行動裝置。app 在 splash screen 前黑畫面太久的其中一個原因正是這一點。Resources 內的 assets 無法動態下載更新,也沒辦法處理 asset 變體。例如貼圖有分 sd、hd 版。Unity 的程式開發人員,從 Unity 5 開始,應該要發展一套能夠方便使用 AssetBundle 的系統,如此便能不再倚賴 Resources。     繼續閱讀
XenStalker's avatar
XenStalker 6月 18, 2017