3DS格式文件按块解析(Java版)
3DS文件格式
在3ds文件中,所有数据都是以块的形式进行存储的,下面是块中的文件格式。理解了块,那我们就能够对3ds文件进行解析了。
3DS块
chunk是3ds文件的基本构成单位。每一个chunk包括一个头和一个主体。chunk是相互嵌套的,这就决定了你必须以递归的方式读取它们。chunk的头又由两部分组成:ID长一个字,chunk的长度(以字节为单位,包括头)长一个双字。ID表示chunk的含义。事实上有上千个chunk,它们构成了一个复杂但灵活的文件系统,你不需要知道所有的就可以顺利的读完整个文件。我基本搞清楚的chunk有:
0x4D4D:根chunk,每一个3ds文件都起自它,它的长度也就是文件的长度。它包含了两个chunk:编辑器,和关键帧。
父chunk:无
子chunk:0x3D3D、0xB000
长度:头长度+子chunk长度
内容:无
0x3D3D:编辑器主chunk,它包含有:网格信息、灯光信息、摄象机信息和材质信息。
父chunk:0x4D4D
子chunk:0x4000、0xafff
长度:头长度+子chunk长度
内容:无
0x4000:网格主chunk,它包含了所有的网格。
父chunk:0x3D3D
子chunk:0x4100
长度:头长度+子chunk长度+内容长度
内容:名称(以空字节结尾的字符串)
0x4100:网格信息,包含网格名称、顶点、面、纹理坐标等。
父chunk:0x4000
子chunk:0x4110、0x4120、0x4140、0x4160
长度:头长度+子chunk长度
内容:无
0x4110:顶点信息。
父chunk:0x4100
子chunk:无
长度:头长度+内容长度
内容:顶点个数(一个字)顶点坐标(三个浮点数一个坐标x、y、z,个数3浮点数)
0x4120:面信息。
父chunk:0x4100
子chunk:0x4130
长度:头长度+子chunk长度+内容长度
内容:面个数(一个字)顶点索引(三个字一个索引1、2、3,个数3字)
0x4130:与网格相关的材质信息。
父chunk:0x4120
子chunk:无
长度:头长度+内容长度
内容:名称(以空字节结尾的字符串)与材质相连的面的个数(一个字)与材质相连的面的索引(个数*字)
0x4140:纹理坐标。
父chunk:0x4100
子chunk:无
长度:头长度+内容长度
内容:坐标个数(一个字)坐标(两个浮点数一个坐标u、v,个数2浮点数)
0x4160:转换矩阵。
父chunk:0x4100
子chunk:无
长度:头长度+内容长度
内容: x轴的向量(三个浮点数u、v、n) y轴的向量(三个浮点数u、v、n) z轴的向量(三个浮点数u、v、n)源点坐标(三个浮点数x、y、z)
0xafff:材质信息。
父chunk:0x4D4D
子chunk:0xa000、0xa020、0xa200
长度:头长度+子chunk长度
内容:无
0xa000:材质名称。
父chunk:0xafff
子chunk:无
长度:头长度+内容长度
内容:名称(以空字节结尾的字符串)
0xa200:纹理帖图。
父chunk:0xafff
子chunk:0xa300
长度:头长度+子chunk长度
内容:无
0xa300:帖图名称。
父chunk:0xa200
子chunk:无
长度:头长度+内容长度
内容:名称(以空字节结尾的字符串)
0xB000:关键帧主chunk,包含所有的关键帧信息。
父chunk:0x4D4D
子chunk:0xB008、0xB002
长度:头长度+子chunk长度
内容:无
0xB008:关键帧的起点和终点。
父chunk:0xB000
子chunk:无
长度:头长度+内容长度
内容:起始帧(一个双字)结尾帧(一个双字)
块解析代码
先将整个3ds文件以10进制数组读入,然后将整个数组分块读取。
// 读取对应块信息
String[] res = new String[6];
TChunk tChunk = new TChunk();
for(int i = 0; i < 6; i++){
res[i] = intToString(results[(int) (index+i)]);
}
String name = res[1]+res[0];
String length = res[5]+res[4]+res[3]+res[2];
tChunk.setChunkId(name);
tChunk.setChunkIndex(index);
tChunk.setChunkLength(Long.parseLong(length, 16));
return tChunk;
通过读取出来的对应块ID进行分别处理
// 读取对应块信息
switch (tChunk.getChunkId()){
case "4D4D":
x = 1;
index += 6;
tChunk.setChunkDescription("文件标志头块");
break;
case "3D3D":
x = 1;
index += 6;
tChunk.setChunkDescription("网格对象的版本号");
break;
case "4000":
if(index+tChunk.getChunkLength()==results.length){
x = 2;
}
else {
x = 1;
}
index += tChunk.getChunkLength();
tChunk.setChunkDescription("对象块");
t3DObject = ReadBinary.readT3DObject(results,tChunk);
t3DObjects.add(t3DObject);
break;
case "0002":
x = 1;
index += tChunk.getChunkLength();
tChunk.setChunkDescription(".3ds文件的版本块");
break;
default:
if(index+tChunk.getChunkLength()==results.length){
x = 2;
}
else {
x = 1;
}
index += tChunk.getChunkLength();
}
tChunks.add(tChunk);