前言:
内容管道的设计十分超前,乃至于至今看来都还算是一个比较新颖的资源处理方式。
本章将深入讲解内容管道的作用及Xnb格式分析。
本章主要内容有:
1.Xna简介
2.内容管道简介
3.内容管道默认支持表
4.内容管道处理流程
5.Xnb格式解析
1.什么是Xna?
Xna是基于DirectX的游戏开发环境,是微软对于Managed DirectX的修正及扩充版本。
Xna可以跨平台运行于Windows、Zune、WindowsPhone以及Xbox360上。
2004年在GDC被公布,直至2006年才开放给开发者使用。
最后版本为Xna4.0,于2012年发布。
2.什么是内容管道(ContentPipeline)?
我们以前做游戏时总会遇到资源加载的问题。
众多格式的支持、特殊格式的解析等。
内容管道简而言之就是将所有格式统一处理,生成统一格式的东西。
换言之,就是将格式分类,然后将这些类别不同格式的内容统一处理为一种格式,然后将之保存。
这样做的好处在于,运行时只需要解析一种格式,而这种格式可以不需要太复杂的处理即可。
即减少了IO操作,又加快了运行时速度。
这就是内容管道的作用了。
3.内容管道默认支持表
类型 | 导入器 | 处理器 | 格式 |
图像 | TextureImporter | TextureProcessor | 所有能被.Net Framework或DirectX支持的图像格式 |
模型 | XImporter FbxImporter | ModelProcessor | x fbx |
音乐 | Mp3Importer WmaImporter | SongProcessor | mp3 wma |
音效 | WavImporter | SongEffectProcessor | wav |
字体 | FontDescriptionImporter | FontTextureProcessor | spritefont |
Shader | EffectImporter | EffectProcessor | fx |
数据 | XmlImporter | 无 | xml |
4.内容管道处理流程
本节我们将以图像为例,简述内容管道的处理及使用。
假设我们有一张图片1.jpg。
编译阶段:
1.TextureImporter将1.jpg解压并读取为原始像素数据。
2.TextureProcessor将原始像素数据包装成Texture2D对象。
3.通过ContentWriter写入平台附加数据并将二进制序列化后的Texture2D对象写入到文件中。
4.输出1.xnb文件,编译完成。
游戏运行阶段:
1.通过ContentReader读取1.xnb文件内的平台数据及反序列化后的Texture2D对象。
2.程序直接调用Texture2D对象内的原始像素数据,完成图像展示。
从以上流程可以看出,复杂及密集的解压缩、解析过程全部在编译阶段就完成了。
游戏运行阶段只需要简单的读取统一的xnb格式并直接反序列化即可读取数据。
因此得到了加载优化的效果。
5.Xnb格式解析
在第4节中我们提到了ContentWriter、ContentReader及xnb格式。
在本节中,我们将深入讲解Xnb格式的组成。
因为Xna4.0是最后版本,也是使用最为广泛的一个版本,因此我们仅对此版本的Xnb格式进行解析。
首先,Xnb格式前3位Byte值以 'XNB' (没有单引号)作为文件标识头。
紧接着第4位Byte有3个可能的值,代表了文件应用于的平台(不同平台文件内容有少许区别),分别是:
'w' = Windows平台
'm' = WindowsPhone
'x' = Xbox360
第5位Byte代表了Xna格式版本,从1到5分别代表了:
1 = Xna1.0
2 = Xna2.0
3 = Xna3.0
4 = Xna3.1
5 = Xna4.0
这里我们假设值永远为5。
第6位Byte值代表了内容表示方式,分别为:
0x00 = 未压缩,使用Reach配置
0x01 = 未压缩,使用HiDef配置
0x80 = 使用LZX压缩,使用Reach配置
0x81 = 使用LZX压缩,使用HiDef配置
第7位-第10位是一个UInt32值,代表了文件总大小(磁盘真实存储大小),但有如下内容需要注意:
若使用了压缩,此值为压缩后的大小加上所有文件头内容的大小。
(以下内容为分支内容,根据第6位表示是否压缩进行分支,红色表示压缩,蓝色表示未压缩)
第11位-第14位是一个UInt32值,代表了未压缩的文件总大小。
第15位第12位是一个7Bit编码Int值(7BitEncodedInt),代表了类型读取器(Type reader)数量。
根据类型读取器数量进行循环。
循环顺序读取内容如下:
String值,代表了类型读取器名称(Type reader name)
Int32值,代表了类型读取器版本,通常是0。
循环完毕后紧跟着读取一个 7BitEncodedInt,代表共享资源数量。
然后读取原始资源数据,这里就是具体的反序列化内容了,加入第4节中就用了Texture2D作为例子。
原始资源数据读取完毕后,开始循环读取共享资源内容,这里是原始资源数据中所需要的公共内容。
循环内容根据原始资源数据而定。
共享资源内容读取完毕后,将共享资源数据依次绑定回原始资源数据内。
完成文件解析。
在线示例:
美国队长(WebGL示例,用JavaScript解析Xnb格式的模型并绘制)
参考: