更为详细的英文资料(用google或者aol搜索 "obj format"即可得到):
http:///wiki/Wavefront_.obj_file
Wavefront OBJ File Format Summary
最详细的资料 obj spec: http://www.martinreddy.net/gfx/3d/OBJ.spec
http://people.cs.clemson.edu/~dhouse/courses/405/docs/brief-obj-file-format.html
http:///lessons/3d-advanced-lessons/obj-file-format/obj-file-format/
看完以上随便一个内容,obj的格式可以说了解了。下面实现对obj文件的读取。
.obj文件中,每一行都有表明该行意义的标志符。对obj的读取中,处理以下标志符
"v"--点的坐标,三维模型为x, y, z的顺序;程序中以
1 typedef struct ObjVector3
2 {
3 ObjFloat x;
4 ObjFloat y;
5 ObjFloat z;
6 } ObjVector3;结构存储。
"vt"--纹理坐标,程序中以
1 typedef struct ObjVector2
2 {
3 ObjFloat x;
4 ObjFloat y;
5 } ObjVector2;结构存储
"vn"--法向量坐标,程序中与“v”的存储结构相同
"f"--面所用到的点坐标/纹理坐标/法向量坐标的索引,
"mtllib"--.obj文件用到的material库文件,“usemtl”标志符用到的material都是从material库文件中取出的
"g"--组group的名称,group里面的"f"可以使用0-N个"usemtl"对面的显示渲染进行控制,当使用了大于1个“usemtl”标志符,程序处理时对于已经读取的"f"很难控制;同时查看obj读取的源码,有的用到了这个标志符,有的没有使用该标志,有的使用了"usemtl"标志符对所读取的"f"面进行分割,本文的处理是使用"usemtl"标志符将"f"面分割为mesh,但是考虑到不同的group可以使用相同的"usemtl”标志(即不同的group都使用了 usemtl AAA),因此将"g"与"usemtl"结合起来,二者的名称作为mesh的名称
"usemtl"--参见"mtllib","g"。一旦使用了该标志符,则在该标志符后面的"f"全部受影响,直到遇到下一个"usemtl"
mesh结构,解析已经读取的“f”存储所面的点坐标/纹理坐标/法向量坐标,其结构为


1 struct Mesh
2 {
3 string name; // name
4 ObjIntd mtl_idx; // the index of material used by mesh
5
6 vector<ObjVector3> positions; // "v" flag
7 vector<ObjVector2> texcoords; // "vt" flag
8 vector<ObjVector3> normals; // "vn" flag
9 vector<ObjDword> indices; // the indices of points of face in positions
10
11 void reset()
12 {
13 mtl_idx = -1;
14
15 name.clear();
16 positions.clear();
17 texcoords.clear();
18 normals.clear();
19 indices.clear();
20 }
21 };View Code
结构中出现的
ObjFloat ObjIntd是一组typedef,具体为


1 typedef int32_t ObjBool;
2 typedef uint8_t ObjByte;
3 typedef uint16_t ObjWord;
4 typedef uint32_t ObjDword;
5 typedef int8_t ObjIntb;
6 typedef int16_t ObjIntw;
7 typedef int32_t ObjIntd;
8
9 typedef float ObjFloat;
10 typedef double ObjDouble;View Code
对obj文件读取的主体程序如下


1 ObjBool obj_file_load(const string& objname)
2 {
3 if (objname.empty())
4 return LIBOBJ_FALSE;
5
6 int mesh_count = 0;
7 Mesh mesh_;
8 string groupname;
9 string usemtl;
10 vector<ObjVector3> positions;
11 vector<ObjVector3> normals;
12 vector<ObjVector2> texcoords;
13 vector<vector<ObjVertexIndex> > faces;
14 map<string, ObjIntd> mtlMap;
15
16 fstream obj_stream;
17 obj_stream.open(objname.c_str(), std::ios_base::in);
18 if (!obj_stream.is_open())
19 return LIBOBJ_FALSE;
20
21 string obj_flag;
22 while (obj_stream.good())
23 {
24 obj_stream >> obj_flag;
25
26 if (obj_flag.empty() || (obj_flag[0] == '#'))
27 {
28 obj_stream.ignore(1024, '\n'); // skip line
29 continue;
30 }
31
32 if (obj_flag == "v") // position flag
33 if (!obj_parse_vector3(obj_stream, positions))
34 return LIBOBJ_FALSE;
35 else if (obj_flag == "vt") // texture coordinate flag
36 if (!obj_parse_vector2(obj_stream, texcoords))
37 return LIBOBJ_FALSE;
38 else if (obj_flag == "vn") // normal flag
39 if (!obj_parse_vector3(obj_stream, normals))
40 return LIBOBJ_FALSE;
41 else if (obj_flag == "g") //group name
42 if (!obj_parse_group(obj_stream, groupname))
43 return LIBOBJ_FALSE;
44 else if (obj_flag == "f") // face flag
45 {
46 vector<ObjVertexIndex> face;
47
48 obj_parse_face(obj_stream, face, positions, texcoords, normals);
49
50 faces.push_back(face);
51 }
52 else if (obj_flag == "mtllib") // Material library
53 {
54 vector<string> materialnames;
55
56 obj_parse_mtllib(obj_stream, materialnames);
57
58 for (unsigned i = 0; i < materialnames.size(); i++)
59 if (!mtl_file_load(get_file_path(objname) + '/' + materialnames[i]))
60 return LIBOBJ_FALSE;
61 }
62 else if (obj_flag == "usemtl")
63 {
64 if (obj_save_mesh(positions, texcoords, normals, faces, groupname+usemtl, mesh_))
65 {
66 m_meshes.back().mtl_idx = mtl_index(usemtl);
67
68 faces.clear();
69 mesh_.reset();
70 }
71
72 obj_parse_group(obj_stream, usemtl);
73 }
74 else
75 {
76 obj_stream.ignore(1024, '\n'); // skip line
77 }
78 }
79
80 if (!obj_stream.eof())
81 return LIBOBJ_FALSE;
82
83 //save mesh data
84 if (obj_save_mesh(positions, texcoords, normals, faces, groupname+usemtl, mesh_))
85 {
86 m_meshes.back().mtl_idx = mtl_index(usemtl);
87
88 faces.clear();
89 mesh_.reset();
90 }
91
92 obj_stream.close();
93
94 return LIBOBJ_TRUE;
95 }View Code
obj文件用到了.mtl格式的material,在对“mtllib”标志符解析时开始读取该.mtl文件,
对于.mtl文件的介绍,请阅读
http://www.fileformat.info/format/material/
http://people.cs.clemson.edu/~dhouse/courses/405/docs/brief-mtl-file-format.html
本程序中存储mtl文件的结构较为简单,只使用了mtl文件中的几个结构而没有全部处理


1 struct ObjMaterial
2 {
3 string name;
4
5 ObjRgb ambient;
6 ObjRgb diffuse;
7 ObjRgb specular;
8
9 ObjWord shininess;
10 ObjByte illumination_model;
11 ObjFloat transparency;
12
13 string ambient_texture;
14 string diffuse_texture;
15 string specular_texture;
16 };View Code
对mtl文件的解析代码:


1 ObjBool mtl_file_load(const string& mtlname)
2 {
3 if (mtlname.empty()) // if obj has no material
4 return LIBOBJ_FALSE;
5
6 ObjMaterial* pmaterial = NULL;
7
8 fstream mtlstream;
9 mtlstream.open(mtlname.c_str(), std::ios_base::in); //open strFileName file
10 if (!mtlstream.is_open())
11 return LIBOBJ_FALSE;
12
13 string mtlflag;
14 while (mtlstream.good())
15 {
16 mtlstream >> mtlflag;
17
18 if (mtlflag == "newmtl")
19 {
20 string materialname;
21 mtlstream >> materialname;
22 if (mtl_index(materialname) != -1)
23 continue;
24
25 pmaterial = new ObjMaterial;
26 pmaterial->name = materialname;
27 m_materials.push_back(pmaterial);
28 }
29 else if (mtlflag == "Ka") //Ambient color
30 if (!mtl_parse_color(mtlstream, pmaterial->ambient))
31 return LIBOBJ_FALSE;
32 else if (mtlflag == "Kd") //Diffuse color
33 if (!mtl_parse_color(mtlstream, pmaterial->diffuse))
34 return LIBOBJ_FALSE;
35 else if (mtlflag == "Ks") //Specular color
36 if (!mtl_parse_color(mtlstream, pmaterial->specular))
37 return LIBOBJ_FALSE;
38 else if (mtlflag == "Tr"/*"d"*/) // Alpha, that is transparent
39 if (!mtl_parse_light(mtlstream, pmaterial->transparency))
40 return LIBOBJ_FALSE;
41 else if (mtlflag == "Ns") //Shininess
42 if (!mtl_parse_light(mtlstream, pmaterial->shininess))
43 return LIBOBJ_FALSE;
44 else if (mtlflag == "illum") //Illumination type
45 if (!mtl_parse_light(mtlstream, pmaterial->illumination_model))
46 return LIBOBJ_FALSE;
47 else if (mtlflag == "map_Ka") //ambient Texture
48 if (!mtl_parse_texture(mtlstream, pmaterial->ambient_texture))
49 return LIBOBJ_FALSE;
50 else if (mtlflag == "map_Kd") //diffuse Texture
51 if (!mtl_parse_texture(mtlstream, pmaterial->diffuse_texture))
52 return LIBOBJ_FALSE;
53 else if (mtlflag == "map_Ks") //specular Texture
54 if (!mtl_parse_texture(mtlstream, pmaterial->specular_texture))
55 return LIBOBJ_FALSE;
56 else
57 mtlstream.ignore(1024, '\n'); // ignore this line, on the assumption that the max characters at this line is 1024.
58 }
59
60 if (!mtlstream.eof())
61 return LIBOBJ_FALSE;
62
63 mtlstream.close();
64 return LIBOBJ_TRUE;
65 }View Code
完整的代码放在了https:///priseup/obj_load
ps: 手上没有数据,还没有进行测试
















