3DS文件在OpenGL的读入和显示
学习了Blender之后,很想将自己设计的模型载入自己编写的程序中,因此考虑了比较常见的3DS文件格式。这回尝试着将3DS文件载入自己写的OpenGL程序并且显示出来。
演示程序下载地址:这里
源代码下载地址:这里
首先查找了许多现成载入3DS格式的例子,发现只有一个程序是可以运行的,于是就拿这个程序的源代码进行研究。同时查看了一些国外的格式说明文档,结合Blender中Outliner中数据的组织,我开始了解3DS格式的组织方式。
3DS文件是二进制的,并且是Autodesk私有格式,很多兼容软件都是根据已知破解的内容来进行读取的,因此不同软件对于它读取的效果会不同,高手们建议只将网格模型导出至3DS,因为光源和摄像机无法保存。
3DS文件的内部有种被称作“块(chunk)”的结构,用来阐述三维场景中各种各样的对象。其实这里所说的“块”和wav文件里面的块差不多,都包含了头(header)和内容(content)。3DS中的块的头包含了ID(占两字节)和长度(占四字节),其中长度则是块的整个长度。而块的内容长度为块的整个长度减去6字节。
举一个例子,主块的ID是0x4D4D,我们可以这样做:读取块ID两个字节,随后读取四字节块的长度(设为length),这样我们知道之后最多还需要读取(length- 6)个字节。
3DS中数据组织结构是树状的,而树中每一个节点也就是块结构,由于树中各个层次有着相似性,根据数据结构中遍历树的知识,我们可以编写深度优先搜索算法,并且使用递归的思想来完成。
3DS树中的叶子节点通常有着特定的解析方法。比如说读到了顶点(ID是0x4110),要求我们先读取两个字节的顶点个数n,再循环n遍读取各个顶点的xyz坐标。
3DS文件内的坐标系与OpenGL和Direct3D的都不同,XY轴确定了水平面,Z轴则是垂直的。在解析的初期我也曾经将它的所有顶点的XYZ值通过交换和去反来对坐标轴进行替换,但是后面需要解析一个模型矩阵,如果仅仅对坐标轴替换而不对模型矩阵进行替换的话,那么解析后形成的模型会出现错位的现象。这会变得非常麻烦。即使可以通过修改模型矩阵的前3×3部分而达到目的,我还是觉得建模的时候通过将模型的坐标系转换成Direct3D的左手坐标系或者OpenGL的右手坐标系会更好一些,同时也会免去一些不必要的转换工作。
解析完3DS文件之后就需要显示它了,很遗憾,目前我使用的Blender导出的3DS不含灯光和摄像机,因此效果没有Blender软件中编辑得那么好。此外,3DS中默认的图元是三角形,也就是说多边形图元在导出的时候会被细分成一个个三角形来保存。因此在OpenGL中直接指定glBegin(GL_TRIANGLES );就好了。
以下是我在Blender中编辑的图像:
下图是程序的运行结果。