作为一个个人项目,我一直在尝试对旧的 Dynamix 游戏 Earthsiege 2 的艺术资产进行逆向工程(该游戏长期以来一直被废弃,最近由当前版权所有者 Hi-Rez 免费发布)。解码图像/纹理是儿戏,但我在使用二进制 3D 模型格式时遇到了麻烦。
作为一些背景,3D 模型保存为 DTS 文件。DTS 是一种专有的二进制格式(little-Endian),是“Dynamix Three-Space”的缩写。我找不到任何有关反转 ES2 时代 DTS 文件的资源。
对于这篇文章,我将专注于启示录。
启示录模型存储在Apoca.dts
. 该文件是这样开始的(十六进制,带注释):
| File size | ? |ChunkMarker|Chunk Length
02|7C 7F 01 00|4B 1F 3D 7F|03 00 1E 00|FC 5F 00
00|FF FF 00 00 0E 08 BF FF CC FF 23 04 01 00 15
00 14 00 70 46 00 00 FF FF 00 00 B7 06 BF FF CC
FF 23 04 1B 00 14 00 14 00 4A 01 00 00 01 00 0C
00 AB 01 FB FF 22 00 7B 05 18 00 0F 00 10 00 06 <-Faces
00 02 00 03 00 04 00 05 00 02 00 05 00 07 00 08
00 0A 00 0B 00 04 00 03 00 03 00 02 00 08 00 0A
00 0B 00 07 00 05 00 04 00 0A 00 08 00 07 00 0B
00 00 00 1D 00 FF 07 00 00 00 00 00 00 24 FF 72 <-Some vertices here
01 82 05 DC 00 72 01 82 05 DC 00 C0 FE 8C 05 24 <-
FF C0 FE 8C 05 00 F8 00 00 00 00 24 FF E8 FE 00 <-
05 24 FF 04 01 60 04 00 08 00 00 00 00 DC 00 04 <-
01 60 04 DC 00 E8 FE 00 05 00 00 7A 07 2A FD 00 <-
00 4F F8 CE FD 00 00 BB FD 55 F8 02 00 00 04 02
00 00 04 00 00 00 14 00 00 00 14 00 00 00 00 FF
FF FF FF FF FF FF FF FF FF FF FF 1B 00 00 00 FF
FF FF FF FF FF FF FF FF FF FF FF 19 00 00 00 FF
FF FF FF FF FF FF FF FF FF FF FF 03 00 14 00 0A
00 00 00 00 00 02 00 04 00 00 00 00 00 03 00 14
有关格式化/颜色编码的分析,请参阅http://postimg.org/image/8e56re90n/
要完整查看文件的前 3 个块,请参阅http://pastebin.com/RTFkdiBd
当前知识
每个 DTS 文件都被分成多个块。第 10-13 个字节是块的开始标记;我认为这是03 00 1E 00
在每个文件中。接下来的四个字节是块的大小,后面总是跟 FF 00。新的块将在前一个结束后立即开始。我现在不知道块是如何分配数据的,但看起来多个块确实包含顶点。这可能与模型明显分为离散部分而不是单个网格的事实有关。
每个顶点是一组 6 个字节,由该顶点的 X、Y 和 Z 坐标的3 个带符号的short组成。此文件中的第一个顶点是 24 FF 62 01 82 05,转换为十进制后的坐标为 -220、354、1401。我提供的示例包含以下顶点:
24 FF 72 01 82 05
DC 00 72 01 82 05
DC 00 C0 FE 8C 05
24 FF C0 FE 8C 05
24 FF E8 FE 00 05
24 FF 04 01 60 04
DC 00 04 01 60 04
DC 00 E8 FE 00 05
这些顶点定义了裤裆。有趣的是,胯部实际上位于文件中定义的 3D 空间中的头部上方,因此它必须在某处进行平移。我已经通过在游戏运行时在 RAM 中编辑它们来测试并验证上述字节包含裤裆,当我单击返回游戏窗口时,这会立即扭曲模型。
请注意,其中一些顶点之间有两组六字节,它们似乎不是顶点(它们不对应于模型上的任何点,并且在 RAM 中更改时没有任何影响)。我不知道这些是什么交易:
00 F8 00 00 00 00
00 08 00 00 00 00
模型的其余部分在整个文件中分段定义。顶点聚集成小组,我认为一次定义一个形状。除了武器和腿,我可以找到所有东西的顶点。腿是动画的,因此它们的定义可能不同,或位于不同的文件中。武器在单独的文件中定义。
在顶点之前是一些小值的短裤,例如 06 00 02 00。这些与人脸有关;我的猜测是他们通过索引引用顶点来定义一个面。我已经通过在游戏运行时在 RAM 中编辑它们来验证这些会影响面部,但还没有完全解码它们。
00 00 00 00 00 00
面和顶点之间总是有 6 个字节的 0 ( )。04 00 00 00 14 00 00 00 14 00 00 00
在顶点结束后不久总是有标记。使用这些知识,我可以通过在这两个标记之间查看来解析文件中的顶点;然而,这是不精确的,我最终得到了一堆垃圾顶点,在模型周围形成了一个部分球壳。
这是我能够从 Apocalypse DTS 文件中读出的顶点点云的渲染图;我在这里过滤掉了一些垃圾顶点,但边缘和中间仍然存在一些。请注意,臀部和胯部位于文件中的躯干上方。
下一步是什么?
我不希望从头到尾解码整个 DTS 文件——它太长太复杂了——但我希望至少能够从文件中读取顶点,希望是面部。
目前我遇到的最大的难题是试图弄清楚如何准确地知道一组面/顶点的开始和结束位置。我的主要问题是如何精确确定一组面/顶点的开始和结束位置,因为它们在每个文件中的位置都不完全相同。您可以发现我遗漏的任何其他信息都很棒,但这是我的主要目标。