Posted by: billconan | September 10, 2006

仙剑奇侠传3模型文件格式分析(1)

前段时间特别喜欢看武林外传, 看到百度贴吧上面有人提议做一个武林外传的游戏。我就跟他们说美工可是大问题,建议他们从现成的游戏里面提取出来。于是我想到了研究仙剑奇侠转3模型文件的格式。把研究的过程在这里计个流水账吧。

仙剑3的资源打包在一个文件中。我对这些打包的东西没什么兴趣,而且网上已经有高手做了拆包的程序,所以就直接拿来用了。

拆包以后会出现很多的贴图文件,同时在模型文件夹下会出现很多.pol文件。估计这个就是模型文件了,因为pol很可能就是polygon的缩写。

模型文件的名称没有什么规律,但是幸运的是有一个叫box.pol的文件(在object目录下),这个很可能说明是一个方盒子的模型。方盒子模型的坐标会比较有特点,因而从这个模型着手分析可能会比较容易。

用16进制的方式打开这个文件进行初步观察,可以观察到如下的特征:

1、文件应该是没有压缩的,理由是文件中重复的字节很多,而且明显能看出很多的字符串。
2、文件的开头有个POLYd字样,应该是文件的合法性标识。打开其他的文件比较了一下,可以证实这个判断。
3、在文件开头有个Box02,可能是模型的名字。
4、紧跟模型名字有很多扩展名,作用不明,结束的位置也不清楚。
5、在这些扩展名之后紧跟了很多数据,含义未知。在这段区域中,每隔固定的长度都会出现 FFFF FFFF 字节。
6、在这段数据之后出现了一些重复的字节,之后是一个图像的文件名xiangzi.tga,应该是该模型的贴图。但是在众多资源中并没有找到这个贴图,现存疑。 这个字符串长度为11,但是在它前面没有指定这个长度的字节存在。其后又是一片空白的区域。
7、 最后存在一些数据区域。

看 到这个文件,我首先发现的就是有很多的 FFFF FFFF 字节存在。这个很可能成为分析这个模型文件的突破口。首先,一般的3D模型的坐标分量是用一个32位的float类型来表示的,而 FFFF FFFF 正好也是32位,这很可能说明这段区域包含了3D模型的顶点坐标。第二,FFFF FFFF 这个数据本身是没有意义的。在文件中它很可能是一个开始或结束的标示符。比如说,在nVidia的Demo中,3D模型就用同样的字节作为开始和结束的符 号。另外,FFFF FFFF 字节的数目刚好是16个,因为一个盒子通常有8个顶点,而16刚好是8的倍数,这也预示着这段数据同顶点的数据之间有一定的关系。但是问什么是顶点的2倍 而不正好是8呢,我感觉可能是前8个是顶点,后8个是贴图坐标。

现在已经假设 FFFF FFFF 是潜在的开始和结束标记,那么它到底是开始还是结束呢。如果假设它是起始标记,那么最后一个顶点的数据将如何结束呢?另外,不难发现,最后一个 FFFF FFFF 后面的数据和上一个 FFFF FFFF 后面的数据区别比较大:

因此我认为这里的 FFFF FFFF 不太可能是起始标记,而应该是结束的标记。

在 顶点数据区之后又很多的重复区域,其间包含了一个贴图文件名,之后又是一些重复的空闲区域。首先这个贴图文件名很可能分割了顶点数据和面的数据。这个判断 没有什么特别严谨的理由,只不过因为obj格式的模型也是这样, 才作出的估计。因为没有在这个数据区域中找到指明了文件名长短(11)的数据,所以我感觉,这个文件应该为贴图文件名分配了一段固定长的空间,而文件名的 长短就限制在这个空间之内,这就是为什么如果文件名没有占满这个空间,后面会出现很多重复空闲的区域。

初步判断在贴图文 件名之后是面的数据,除了上面提到的原因以外,还有几个因素可以肯定这个假设。首先,这些数据明显是以4个字为一个单位。这就说明,这段数据不太可能是浮 点类型的数据。我们知道,在3D模型中,每个面通常包含了组成这个面的3个顶点的编号,因而是整型的数据。虽然这里的数据是16位的,而不是整形通常的 32位,但是说不定它是用的short类型。另外一个重要的特点是,这个数据区域的开始有个明显的递增的趋势,这个也是面数据的一个特征。因为一个面的顶 点通常是连续建立的,因而编号递增变化。最后,这个区域中的数据,如果是short类型的话,刚好都不超过16,因为已知有16个顶点信息了,而这段数据 很可能就是顶点的编号。这也说明那16个点也许不是前8个顶点,后8个贴图坐标,而是一样的顶点信息。那为什么有16个呢

经过初步观察可以得到如下的结论或者说猜测:

1、文件开头有一个固定的标识。
2、之后是模型的名称和不明的数据
3、紧接着是顶点数据,每个顶点由 FFFF FFFF字节结束
4、然后是贴图文件名
5、最后是面数据,short型

到 这一步还有几个问题不太明了,第一,如果最后面是面数据的话,到底是triangle strip还是triangle list呢,不得而知。第二,为什么在第0x27那行会有一个连续的 0000 0000 呢,这个作为面数据没有什么意义。第三,每一个顶点数据包含了20个字节的信息,初步估计是3个坐标(12个字节)和2个贴图坐标(8个字节),但是如果 贴图坐标包含在顶点信息中,为什么会有16个顶点信息而非8个呢?不过看到这一步,只有写个程序试验一下了。

这个是伪代码:

打开文件,将文件指针调整到0x58的位置开始读取一个20个字节的数据
while(最后面是 FFFF FFFF)
{
以浮点的形式输出这个点的所有信息
再读取一个点
}

这个程序运行之后可以观察到,每个顶点输出的5个浮点数中,前两个浮点数是一个在0和1之间的数,而后面的3个数范围比较大。这说明前面的2个数应该是贴图坐标,而后面的是顶点的3个坐标。于是可以假定顶点数据的格式是这样的:

struct vertex
{
float u;
float v;
float x;
float y;
float z;
};

为什么把贴图坐标放在坐标之前呢,这个是比较奇怪的一点。

把 顶点取出之后,还要看一下这些顶点是不是构成一个盒子的造型。我用opengl简单地渲染了一下,确实。有了顶点的数据,需要分析面的数据了。刚才提到, 在面的数据中存在连续的顶点编号,这个是没意义的。但是这些数据只存在于数据区的前面,后面的数据都比较正常。所以我从后往前数,看到什么位置出现了不正 常。因为先前也提到,一般面的数据呈现一种递增的趋势,而且一般都从编号0开始,所以我认为0x280应该是面数据的开始。如果每个面包含3个顶点的话, 每个面应该占有6个字节,而从0x280到文件尾有60个字节。如果这些面是triangle list的话,那么刚好有10个面。但是,一个盒子应该有6个面,每个面应该由2个三角面所组成,这样算下来应该有12个面的数据,但是为什么这里只有 10个呢。另外注意到,紧接着面数据区前面的一个32位整型数据(0x27c)刚好是0xa,也就是10。会不会这个就是面的数目呢。我比对了其他的文 件,应该没错。

于是,面的数据应该是这样的:

int faceCount;
struct face
{
short v1;
short v2;
short v3;
};

按照这样的格式将模型输出成obj格式,然后用3D Max导入。发现模型是一个没有底面的盒子。这解释了为什么最后的面数据只有10个,而不是12个。因为在游戏中,为了加速渲染速度,模型需要尽量精简, 而一个盒子贴近地面的那一个面又通常不可见,因此模型中省略了底面。另外,模型中存在不少位置重复的点,现在看来是因为每个点的贴图坐标只能允许有一组, 所以如果要一个点有不同的贴图坐标,只能定义好几个点,这些点位置相同,但是贴图坐标不同。

初步拆解了这个模型文件之后,要进一步讨论它的适用型。把这个程序在其它的模型身上试验了一下,又成功拆开了j13.pol这个文件。 但是导入到3D Max之后,贴图坐标似乎有些不太正常。但是一开始我没有注意到这个问题。另外又试了几个文件,都出了问题。

如果要这个拆解的程序能够应用到更多的模型身上,必须要假设所有模型的顶点信息的起点都是0x58,并且包含贴图信息的数据区的长度是一致的。

我 打开那些不能拆解的模型文件,发现它们的顶点数据区的起始都不是ox58,也就是说我的第一个假设有问题。但是贴图信息的数据区长度似乎是一致的。另外一 个问题就是,这些问题文件包含的模型不止一个,它们都存在多个顶点数据区,面数据区和贴图数据区。这很可能说明,未知的文件头长度和模型文件所包含的模型 数目是相关的。

另外我注意到在0x8的位置上有个数,最开始我以为是指明模型名字长度的一个数值。但是比较box.pol文件,发现明显不 对。j13.pol的这个数值也是1,但是打不开的那些文件中这个数字就不是1了。这说明,这个数字表示模型中所含模型的个数。打开几个文件数了一下,证 实了这个猜想。

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: