Fork me on GitHub

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

参考:

posted @ 2017-03-02 12:35  Pink-Floyd  阅读(4327)  评论(1编辑  收藏  举报