常用三维模型文件结构解析

参考网址:

(1)http://www.martinreddy.net/gfx/3d/(3DS、OBJ等3D模型文件数据结构分析)

(2)http://www.the-labs.com/Blender/3DS-details.html

(3)https://people.sc.fsu.edu/~burkardt/data/data.html

 

1. 3DS模型文件结构

3DS模型文件有许多的块组成。块是3DS文件的基本组成单位,每个块首先描述其信息类别,即该块是如何组成的。具体为:每个块由块头和主体内容组成。其中块头又包含块ID和块长度两个信息字段。其中块的ID字段是一个整形数据,用来标识块的信息类别;块长度是一个长整形数据,它指出了下一个块相对于该块的偏移字节数。

这样即是你并不了解这个块的内容也可以跳过该块并迅速找到下一个块的位置。和其他许多的二进制文件一样,3DS二进制文件也是按照低位在前高位在后的顺序组织的,例如,对于整形数据0X4B5C两字节的十六进制数据,4B是低位数据,而5C是高位数据。又如长整型数据0x4B5C6D7E,它的4B5C是低位比特,6D7E则是高位比特。

为了直观化,我们用一个结构图来展现它的逻辑结构,如图4-1所示:

图4-1  3DS文件结构示意图

从上述的结构图中我们可以看到,每个块在物理结构上是一个层次结构,不同的块层次结构也不一样。每个3DS文件中有一个基本块。其ID是4D4D,每个3DS文件都是由这样的块开头。基本块内的块称之为主块,主块包括编辑器块和关键帧块,其中编辑器块又包括材质列表块、配置块等等。这里面的块又包括一些别的块。总而言之,3DS文件的块构成是一种嵌套结构。故而,由于块结构的特殊性决定了我们读取它的方法可以通过函数的递归来实现。

1.13D模型数据结构定义

上面是对3DS文件结构示意图的分析,下面的一个表格列出主要的八个常见的块,表中指出了相应的块ID号和块信息。

表 4-1  3DS文件中几个主要的块和相关信息

块ID号

包含信息

块ID号

包含信息

0xAFFF

材质信息开始

0xA000

材质名称

0xA300

材质的纹理名称

0x4000

材质名称

0x4110

对象中顶点信息

0x4120

模型中对象信息

0x4130

与三角面相关的材质信息

0x4140

纹理坐标

(1)为了方便我们程序的书写,我们定义如下的宏定义:

// 基本块(Primary Chunk),位于文件的开始

#define PRIMARY 0x4D4D

// 主块(Main Chunks)

#define OBJECTINFO 0x3D3D        // 网格对象的版本号

#define VERSION 0x0002        // .3ds文件的版本

#define EDITKEYFRAME 0xB000        // 所有关键帧信息的头部

// 对象的次级定义(包括对象的材质和对象)

#define MATERIAL   0xAFFF        // 保存纹理信息

#define OBJECT     0x4000        // 保存对象的面、顶点等信息

// 材质的次级定义

#define MATNAME 0xA000        // 保存材质名称

#define MATDIFFUSE 0xA020        // 对象/材质的颜色

#define MATMAP 0xA200        // 新材质的头部

#define MATMAPFILE 0xA300        // 保存纹理的文件名

#define OBJECT_MESH 0x4100        // 新的网格对象

// OBJECT_MESH的次级定义

#define OBJECT_VERTICES 0x4110      // 对象顶点

#define OBJECT_FACES    0x4120      // 对象的面

#define OBJECT_MATERIAL    0x4130      // 对象的材质

#define OBJECT_UV      0x4140      // 对象的UV纹理坐标

图 4-2  3DS文件宏定义

(2)3DS文件块的数据结构定义

// 定义3D点的类,用于保存模型中的顶点

class CVector3

{

public:

  float x, y, z;

};

// 定义2D点类,用于保存模型的UV纹理坐标

class CVector2

{

public:

  float x, y;

};

// 面的结构定义

struct tFace

{

  int vertIndex[3];      // 顶点索引

  int coordIndex[3];      // 纹理坐标索引

};

// 材质信息结构体

struct tMaterialInfo

{

  char strName[255];      // 纹理名称

  char strFile[255];      // 如果存在纹理映射,则表示纹理文件名称

  BYTE color[3];        // 对象的RGB颜色

  int texureId;        // 纹理ID

  float uTile;        // u 重复

  float vTile;        // v 重复

  float uOffset;       // u 纹理偏移

  float vOffset;        // v 纹理偏移

} ;

// 对象信息结构体

struct t3DObject

{

  int numOfVerts;      // 模型中顶点的数目

  int numOfFaces;      // 模型中面的数目

  int numTexVertex;      // 模型中纹理坐标的数目

  int materialID;      // 纹理ID

  bool bHasTexture;      // 是否具有纹理映射

  char strName[255];      // 对象的名称

  CVector3 *pVerts;      // 对象的顶点

  CVector3 *pNormals;    // 对象的法向量

  CVector2 *pTexVerts;    // 纹理UV坐标

  tFace *pFaces;        // 对象的面信息

};

// 模型信息结构体

struct t3DModel

{

  UINT texture[MAX_TEXTURES];

  int numOfObjects;          // 模型中对象的数目

  int numOfMaterials;          // 模型中材质的数目

  vector pMaterials;  // 材质链表信息

  vector pObject;      // 模型中对象链表信息

};

图 4-3  3DS文件块的数据结构定义

1.2 定义3DS文件的基本构成块

// 保存块信息的结构

struct tChunk

{

  unsigned short int ID;          // 块的ID   

  unsigned int length;          // 块的长度

  unsigned int bytesRead;          // 需要读的块数据的字节数

};

    图 4-4  3DS文件的基本构成块定义

1.3 3DS模型数据的读入类定义

我们定义一个读入3D模型数据的类为CLoad3DS,源代码见图4.10:

class CLoad3DS

{

public:

  CLoad3DS();                // 初始化数据成员

  // 装入3ds文件到模型结构中

  bool Import3DS(t3DModel *pModel, char *strFileName);

private:

  // 读入一个纹理

  int BuildTexture(char *szPathName, GLuint &texid);

  // 读一个字符串

  int GetString(char *);

  // 读下一个块

  void ReadChunk(tChunk *);

  // 读下一个块

  void ProcessNextChunk(t3DModel *pModel, tChunk *);

  // 读下一个对象块

  void ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *);

  // 读下一个材质块

  void ProcessNextMaterialChunk(t3DModel *pModel, tChunk *);

  // 读对象颜色的RGB值

  void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk);

  // 读对象的顶点

  void ReadVertices(t3DObject *pObject, tChunk *);

  // 读对象的面信息

  void ReadVertexIndices(t3DObject *pObject, tChunk *);

  // 读对象的纹理坐标

  void ReadUVCoordinates(t3DObject *pObject, tChunk *);

  // 读赋予对象的材质名称

  void ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk);

  // 计算对象顶点的法向量

  void ComputeNormals(t3DModel *pModel);

  // 关闭文件,释放内存空间

  void CleanUp();

  // 文件指针

  FILE *m_FilePointer;

  tChunk *m_CurrentChunk;

  tChunk *m_TempChunk;

};

图 4-5 3DS模型数据读入类的定义

1.43DS文件结构详细解析

1.4.1 3DS模型文件读取规则

3ds文件的读取规则如下:

字节:直接读取;

字:先读低位字节,后读高位字节,如ed 3c读出后的字为3ced;

双字:先读低位字,后读高位字,如ed 3c 25 43读出后的双字为43 25 3c ed;

浮点数:直接读取四个字节。

1.4.2 3DS文件中的主要CHUNK

chunk是3ds文件的基本构成单位。每一个chunk包括一个头和一个主体。chunk是相互嵌套的,这就决定了你必须以递归的方式读取它们。chunk的头又由两部分组成:ID长一个字,chunk的长度(以字节为单位,包括头)长一个双字。ID表示chunk的含义。事实上有上千个chunk,它们构成了一个复杂但灵活的文件系统,你不需要知道所有的就可以顺利的读完整个文件。需要清楚的chunk重要有:

(1)0x4D4D:根chunk,每一个3ds文件都起自它,它的长度也就是文件的长度。它包含了两个chunk:编辑器,和关键帧。

父chunk:无

子chunk:0x3D3D、0xB000

长度:头长度+子chunk长度

内容:无

(2)0x3D3D:编辑器主chunk,它包含有:网格信息、灯光信息、摄象机信息和材质信息。

父chunk:0x4D4D

子chunk:0x4000、0xafff

长度:头长度+子chunk长度

内容:无

(3)0x4000:网格主chunk,它包含了所有的网格。

父chunk:0x3D3D

子chunk:0x4100

长度:头长度+子chunk长度+内容长度

名称(以空字节结尾的字符串)

(4)0x4100:网格信息,包含网格名称、顶点、面、纹理坐标等。

父chunk:0x4000

子chunk:0x4110、0x4120、0x4140、0x4160

长度:头长度+子chunk长度

内容:无

(5)0x4110:顶点信息。

父chunk:0x4100

子chunk:无

长度:头长度+内容长度

内容:

顶点个数(一个字)

顶点坐标(三个浮点数一个坐标x、y、z,个数*3*浮点数)

(6)0x4120:面信息。

父chunk:0x4100

子chunk:0x4130

长度:头长度+子chunk长度+内容长度

内容:

面个数(一个字)

顶点索引(三个字一个索引1、2、3,个数*3*字)

(7)0x4130:与网格相关的材质信息。

父chunk:0x4120

子chunk:无

长度:头长度+内容长度

内容:

名称(以空字节结尾的字符串)

与材质相连的面的个数(一个字)

与材质相连的面的索引(个数*字)

(8)0x4140:纹理坐标。

父chunk:0x4100

子chunk:无

长度:头长度+内容长度

内容:

坐标个数(一个字)

坐标(两个浮点数一个坐标u、v,个数*2*浮点数)

(9)0x4160:转换矩阵。

父chunk:0x4100

子chunk:无

长度:头长度+内容长度

内容:

x轴的向量(三个浮点数u、v、n)

y轴的向量(三个浮点数u、v、n)

z轴的向量(三个浮点数u、v、n)

源点坐标(三个浮点数x、y、z)

(10)0xafff:材质信息。

父chunk:0x4D4D

子chunk:0xa000、0xa020、0xa200

长度:头长度+子chunk长度

内容:无

(11)0xa000:材质名称。

父chunk:0xafff

子chunk:无

长度:头长度+内容长度

内容:名称(以空字节结尾的字符串)

(12)0xa020:满射色。

父chunk:0xafff

子chunk:0x0011、0x0012

长度:头长度+子chunk长度

内容:无

(13)0xa200:纹理贴图。

父chunk:0xafff

子chunk:0xa300

长度:头长度+子chunk长度

内容:无

(14)0xa300:贴图名称(纹理贴图的文件名)。

父chunk:0xa200

子chunk:无

长度:头长度+内容长度

内容:

名称(以空字节结尾的字符串)

(15)0xB000:关键帧主chunk,包含所有的关键帧信息。

父chunk:0x4D4D

子chunk:0xB008、0xB002

长度:头长度+子chunk长度

内容:无

(16)0xB008:关键帧的起点和终点。

父chunk:0xB000

子chunk:无

长度:头长度+内容长度

内容:

起始帧(一个双字)

结尾帧(一个双字)

(17)0xB002:网格的关键帧信息。

父chunk:0xB000

子chunk:0xB010、0xB011、0xB013、0xB020、0xB021、0xB022、0xB030

长度:头长度+子chunk长度

内容:无

(18)0xB010:关键帧的层次信息,包括名称和上一级关键帧的索引,名称与它指向的网格名称一致。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

名称(以空字节结尾的字符串)

两个未知的字

上一级关键帧的索引(一个字)

(19)0xB011:关键帧的dummy名称,我不知道dummy在这里的具体含义,但只要你在上一个chunk中读到的名称是“$$$DUMMY”那么你就要到这里来读它真正的名称。因为这说明它指向的不是网格而是虚拟的组。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

名称(以空字节结尾的字符串)

(20)0xB013:支点坐标。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:三个浮点数x,y,z

(21)0xB020:移动的关键帧信息。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

五个未知的字

帧个数(一个字)

一个个数那么多的循环结构{

帧索引(一个字)

一个未知的双字

移动的向量(三个浮点数x,y,z)

}

(22)0xB021:转动的关键帧信息。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

五个未知的字

帧个数(一个字)

一个个数那么多的循环结构{

帧索引(一个字)

一个未知的双字

转动角度(一个浮点数)

绕之转动的向量(三个浮点数x,y,z)

}

(23)0xB022:缩放的关键帧信息。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

五个未知的字

帧个数(一个字)

一个个数那么多的循环结构{

帧索引(一个字)

一个未知的双字

伸缩的向量(三个浮点数x,y,z)

}

(24)0xB030:关键帧的索引。

父chunk:0xB002

子chunk:无

长度:头长度+内容长度

内容:

关键帧的索引(一个字)

1.4.3 以下的chunk可能出现在任何chunk中

(1)0x0010:浮点数格式的颜色。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:颜色(三个浮点数red,green,blue)

(2)0x0011:字节格式的颜色。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:颜色(三个字节red,green,blue)

(3)0x0012:字节格式的gamma矫正。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:颜色(三个字节red,green,blue)

(4)0x0013:浮点数格式的gamma矫正。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:颜色(三个浮点数red,green,blue)

(5)0x0030:字格式的百分比。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:百分比(一个字0~100)

(6)0x0031:浮点数格式的百分比。

父chunk:任何可能的chunk

子chunk:无

长度:头长度+内容长度

内容:百分比(一个浮点数0~100)

 

2. OBJ模型文件与MTL文件

参考网址:http://blog.csdn.net/pslstar/archive/2008/11/11/3277990.aspx

OBJ文件是Wavefront公司为它的一套基于工作站的3D建模和动画软件“Advanced Visualizer”开发的一种文件格式。OBJ3.0格式支持多边形(Polygon)、直线(Lines)、表面(Surfaces)和自由形态曲线(Free-form Curves)。直线和多角形通过它们的点来描述,曲线和表面则根据于它们的控制点和依附于曲线类型的额外信息来定义。这些信息支持规则和不规则的曲线,包括那些基于贝塞尔(Bezier)曲线、B样条(B-spline)、基数(Cardinal/Catmull-Rom样条)和泰勒方程(Taylor equations)的曲线。

2.1 OBJ文件的基本特点

(1)OBJ是一种3D模型文件,因此不包含动画、材质特性、贴图路径、动力学、粒子等信息。

(2)OBJ文件主要支持多边形(Polygons)模型。

(3)OBJ文件支持三个点以上的面。

(4)OBJ文件支持法线和贴图坐标。

(5)OBJ文件不支持有孔的多边形面

(6)OBJ文件不包含面的颜色定义信息,不过可以引用材质库,材质库信息储存在一个后缀是“.mtl”的独立文件中。关键字“mtllib”即材质库的意思。材质库中包含材质的漫射(diffuse),环境(ambient),光泽(specular)的定义值,“usemtl”指定了材质之后,以后的面都是使用这一材质,直到遇到下一个“usemtl”来指定新的材质。

(7)3DS Max导出的OBJ文件与Maya导出的OBJ文件不同,因为Maya导出的OBJ文件不包含缺少材质信息。

2.2OBJ文件的基本结构

OBJ 文件由一行行文本组成,注释行以一个“井”号(#)为开头,空格和空行可以随意加到文件中以增加文件的可读性。有字的行都由一两个标记字母也就是关键字(Keyword)开头,关键字可以说明这一行是什么样的数据。多行可以逻辑地连接在一起表示一行,方法是在每一行最后添加一个连接符(\)。注意连接符(\)后面不能出现空格或tab格,否则将导致文件出错。下列关键字可以在OBJ文件使用(在这个列表中,关键字根据数据类型排列,每个关键字有一段简短描述)

(1)顶点数据(Vertex data):

  v  几何体顶点 (Geometric vertices)

  vt  贴图坐标点 (Texture vertices)

  vn  顶点法线 (Vertex normals)

  vp  参数空格顶点 (Parameter space vertices)

(2)自由形态曲线(Free-form curve)/表面属性(surface attributes):

  deg  度 (Degree)

  bmat  基础矩阵 (Basis matrix)

  step  步尺寸 (Step size)

  cstype  曲线或表面类型 (Curve or surface type)

(3)元素(Elements):

  p 点 (Point)

  l 线 (Line)

  f 面 (Face)

  curv  曲线 (Curve)

  curv2  2D曲线 (2D curve)

  surf  表面 (Surface)

(4)自由形态曲线(Free-form curve)/表面主体陈述(surface body statements):

  parm  参数值 (Parameter values )

  trim  外部修剪循环 (Outer trimming loop)

  hole  内部整修循环 (Inner trimming loop)

  scrv  特殊曲线 (Special curve)

  sp  特殊的点 (Special point)

  end  结束陈述 (End statement)

(5)自由形态表面之间的连接(Connectivity between free-form surfaces):

  con  连接 (Connect)

(6)成组(Grouping):

  g  组名称 (Group name)

  s  光滑组 (Smoothing group)

  mg  合并组 (Merging group)

  o  对象名称 (Object name)

(7)显示(Display)/渲染属性(renderattributes):

bevel  导角插值 (Bevel interpolation)

  c_interp  颜色插值 (Color interpolation)

  d_interp  溶解插值 (Dissolve interpolation)

  lod  细节层次 (Level of detail)

  usemtl  材质名称 (Material name)

  mtllib  材质库 (Material library)

  shadow_obj  投射阴影 (Shadow casting)

  trace_obj  光线跟踪 (Ray tracing)

  ctech  曲线近似技术 (Curve approximation technique)

  stech  表面近似技术 (Surface approximation technique)

OBJ文件以纯文本的形式存储了模型的顶点、法线和纹理坐标和材质使用信息。OBJ文件的每一行,都有极其相似的格式。在OBJ文件中,每行的格式如下:

前缀  参数1 参数2 参数3 ...

其中,前缀标识了这一行所存储的信息类型。参数则是具体的数据。OBJ文件的前缀可以有:

前缀

说明

v

表示本行指定一个顶点。

此前缀后跟着3个单精度浮点数,分别表示该定点的X、Y、Z坐标值

vt

表示本行指定一个纹理坐标。

此前缀后跟着两个单精度浮点数。分别表示此纹理坐标的U、V值

vn

表示本行指定一个法线向量。

此前缀后跟着3个单精度浮点数,分别表示该法向量的X、Y、Z坐标值

f

表示本行指定一个表面(Face)。

一个表面实际上就是一个三角形图元。此前缀行的参数格式后面将详细介绍。

usemtl

此前缀后只跟着一个参数。该参数指定了从此行之后到下一个以usemtl开头的行之间的所有表面所使用的材质名称。该材质可以在此OBJ文件所附属的MTL文件中找到具体信息。

mtllib

此前缀后只跟着一个参数。该参数指定了此OBJ文件所使用的材质库文件(*.mtl)的文件路径

表 OBJ文件中的前缀

2.3MTL文件(Material Definitions for OBJ File)

参考网址:http://www.fileformat.info/format/material/

An MTL file is an auxilliary file containing definitions ofmaterials that may be accessed by an OBJ file. The OBJ file must specify thename of the MTL file by a command such as

       mltlib file_name

It is presumed that the MTL file names and defines variousmaterials, such as, perhaps, "shinyred" or "iron". Then,within the OBJ file, the command

       usemtl shinyred

indicates that all subsequence faces should be rendered with thismaterial, until a new material is invoked.

An MTL file contains a sequence of definitions of materials. Eachdefinition begins with a newmtl statement that defines the name of thematerial, followed by lines specifying particular properties.

MTL File Characteristics:  ASCII;

Comments begin with a '#' character in column 1. Blank lines may beinserted for clarity. Otherwise, the file consists of a sequence of newmtlstatements, followed by a definition of various properties for that material.

The quantities that may be defined for a material include:

Ka r g b

    defines the ambient colorof the material to be (r,g,b). The default is (0.2,0.2,0.2);

Kd r g b

    defines the diffuse colorof the material to be (r,g,b). The default is (0.8,0.8,0.8);

Ks r g b

    defines the specular colorof the material to be (r,g,b). This color shows up in highlights. The defaultis (1.0,1.0,1.0);

d alpha

    defines the transparencyof the material to be alpha. The default is 1.0 (not transparent at all) Some formats use Tr instead of d;

Tr alpha

    defines the transparencyof the material to be alpha. The default is 1.0 (not transparent at all). Someformats use d instead of Tr;

Ns s

    defines the shininess ofthe material to be s. The default is 0.0;

illum n

    denotes the illuminationmodel used by the material. illum = 1 indicates a flat material with nospecular highlights, so the value of Ks is not used. illum = 2 denotes thepresence of specular highlights, and so a specification for Ks is required.

map_Ka filename

    names a file containing atexture map, which should just be an ASCII dump of RGB values;

 

 

 

 

 

你可能感兴趣的:(应用软件推荐与应用)