AssetBundle文件結構淺析


壓縮方式:

AssetBundle壓縮后大致文件組成:

LZMA:

壓縮數據的頭有13個字節,前5個字節是lzma解壓縮的API需要插入的props,

接下來的4字節是解壓縮后的數據庫長度。使用時需要整體解包,優點是打包后體積小,

缺點是解包時間長,導致加載時間長。

LZ4格式:

相較LZMA會生成更大的壓縮文件,但優點是使用時不需要整體解壓。

LZ4是一種基於chunk的算法,加載對象時只有相應的chunk會被解壓。

該格式需要Unity5.3以上的版本,以前的版本並不支持。

不同壓縮方式使用加載API對比:

API

未壓縮

LZ4(塊壓縮)

Unity5.3后

LZMA(流壓縮)

默認壓縮方式

WWW*

內存:未壓縮

無需額外的處理

內存:LZ4HC壓縮

無需額外處理

內存:LZ4壓縮

LZMA解壓+下載過程中LZ4壓縮

LoadFromCacheOrDownload

內存:無需額外內存

需要從硬盤讀取

內存:無需額外內存

需要從硬盤讀取

內存:無需額外內存

需要從硬盤讀取

LoadFromMemory(Async)

內存:未壓縮

無需額外的處理

內存:LZ4HC壓縮

無需額外處理

內存:LZ4壓縮

LZMA解壓+LZ4壓縮

LoadFromFile(Async)

內存:未壓縮

無需額外的處理

內存:無需額外內存

需要從硬盤讀取

內存:LZ4壓縮

LZMA解壓+LZ4壓縮+從硬盤讀取

WebRequest

(同時支持Caching)

內存:未壓縮

一般無需額外處理,

讀Cache需讀取硬盤

內存:LZ4HC壓縮

一般無需額外處理,

讀Cache需讀取硬盤

內存:LZ4壓縮

LZMA解壓+下載過程LZ4壓縮,讀Cache需讀取硬盤

AssetBundle文件結構:

通常情況下AssetBundle文件組成:

場景打包AssetBundle組成結構

AssetBundle由兩部分組成:頭部(header)數據部分(data segment)

  1. 頭部保存了版本號、數據類型、文件信息、是否壓縮等這些描述信息。

    文件信息記錄了數據部分里面的所有單個資源的文件名以及在整個AssetBundle中

    文件offset和size,通過這個信息可以直接獲取到AssetBundle中的某一個文件的數據。

    從Unity5.3版本開始這部分數據會單獨生成一個AssetBundle同名的.manifest文件。

  2. 數據塊保存了在build AssetBundle時候標記的textures、prefabs、materials等資源文件

文件頭結構(未壓縮):文件字節流以'\0'結尾,且為大端方式儲存。

 1 // AssetBundle文件頭結構
 2 struct AssetBundleFileHead {
 3     struct LevelInfo {
 4         unsigned int PackSize;
 5         unsigned int UncompressedSize;
 6     };
 7 
 8     string FileID;
 9     unsigned int Version; // bundle格式版本 3.5~4.x : Version == 3
10     string MainVersion; // 
11     string BuildVersion;
12     size_t MinimumStreamedBytes;
13     size_t HeaderSize;
14     size_t NumberOfLevelsToDownloadBeforeStreaming;
15     size_t LevelCount;
16     LevelInfo LevelList[];
17     size_t CompleteFileSize;
18     size_t FileInfoHeaderSize;
19     bool Compressed;
20 };

一個 AssetBundle是由多個asset 文件打包而成,順序打包了這些 asset 。

序列化成這樣的結構:

 1 // asset 文件頭結構
 2 struct AssetFileHeader {
 3     struct AssetFileInfo {
 4         string name;
 5         size_t offset; //除去 HeaderSize 后的偏移量
 6         size_t length;
 7     };
 8     size_t FileCount;
 9     AssetFileInfo File[];
10 };

分解出被打包在一起的多個 Asset 了,offset 表示的是除去 HeaderSize 后的偏移量。

可以用 HeaderSize 加上那個部分的 offset 得到這個部分相對於整個 bundle 的文件偏移。

對於每個 asset ,又有它自己的數據頭。數據頭除了基本的數據頭結構 AssetHeader 外,

還有額外的三個部分:

1 // asset數據頭
2 struct AssetHeader {
3     size_t TypeTreeSize; // TypeTree對AssetBundle是可選的
4     size_t FileSize;
5     unsigned int Format; // 根據Unity版本決定
6     size_t dataOffset;
7     size_t Unknown;
8 };

在發布到移動設備上時,TypeTree 是不打包到 asset bundle 中的。

每個 asset 對象,都有一個 Class ID ,可以在 TypeTree 中查到如何反序列化。

Class ID的和具體類型的對應關系,在 Unity3d 的官方文檔 可以查到。

接下來是每個 AssetObject 的描述數據。

 1 // Object 數據頭
 2 struct ObjectHeader {
 3     struct ObjectInfo {
 4         // int為"小端編碼"的4字節整數
 5         int offset;
 6         int length;
 7         int pathID;
 8         byte classID[8];
 9     };
10     int ObjectCount;
11     ObjectInfo Object[];
12 };

如果想取得正確的相對整個文件的位置:

應該是文件的 HeaderSize + asset.offset + asset.dataOffset + object.Offset

接在 ObjectHeader 后的是 AssetRef 表,記錄了 Asset 的引用關系。

用於指明這個 bundle 內 asset 對外部 asset 的引用情況。

AssetRefTable 結構如下:

 1 struct AssetTable {
 2     struct AssetRef {
 3         byte GUID[16];
 4         int type;
 5         string filePath;
 6         string assetPath;
 7     };
 8     int Count;
 9     byte Unknown;
10     vector Refs;
11 };

每次同樣的asset,打包后的包大小都不一致是因為生成AssetBundle的時候用了lzma壓縮,

只要壓縮前的數據有一點點不一樣,那lzma 后的結果就幾乎完全不一樣。
想要得到一模一樣的AssetBundle包,要在BuildAssetBundleassetBundleOption

|BuildAssetBundleOptions.DeterministicAssetBundle來確保文件的唯一性。

Manifest文件:

Manifest文件僅用於檢查增量構建,運行時不需要。因此不需要打包進正式發行的游戲中。

每個AssetBundle都有一個manifest文件,包含如下信息:

  1. CRC(循環冗余碼):資源文件的哈希碼,在該AssetBundle中的所有資源有一個單一的哈希碼,用於檢查增量的構建。
  2. Type tree哈希碼:在該AssetBundle中所有類型有一個單一的哈希碼,用於檢查增量的構建。
  3. Class types:該AssetBundle中所有的類類型。當為type tree做增量構建檢查時將產生一個新的哈希碼。
  4. Asset names:該AssetBundle中所有明確包含的資源名字, 依賴於該AssetBundle的其他AssetBundle。

不同格式文件的打包類型:

文件格式

支持后綴名

打包后的類型

文本

txt xml

TextAsset保存在TextAsset的text屬性中

二進制

bytes

數據保存在TextAsset的bytes屬性中

Prefab

prefab

GameObject 需instantiate實例化才可以使用

FBX

fbx

添加了Animator為 GameObject,需Instantiate實例化

Mecanim

N/A

GameObject Mecanim中必須制作為預制件進行加載

Legacy動畫

N/A

同上

圖片

bmp jpg png

Texture2D Sprite

音樂

aiff mp3 ogg

Audio Clip

ScriptableObject

asset

Scriptable Object派生類

Unity Studio輸出格式:

Unity Studio和Disunity解包工具基本都是首先處理AssetBundle包,讀入stream中decode。

首先檢測簽名,查看AssetBundle打包的平台,根據不同平台來選擇不同的加載方式。

然后根據偏移和數據ID來解析stream,並將數據轉為相關的文件格式。

資源類型

輸出格式

圖片

pvr 和dds

音頻

mp3

網格

txt

Shader

shader

配置表

txt

參考:


免責聲明!

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



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