在最近的3D编程中,想开始做一些多模型的Demo,而网上显然没有那么多直接可供DirectX使用的模型文件(.x),而3D模型文件格式中的obj文件则具有较好的通用性,不仅支持各类3D建模软件的互相导入导出,在Maya上还可以直接读写。
OBJ文件结构:
以一个立方体模型的obj文件为例:
# 一些注释
mtllib cube.mtl
g default
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.998008 0.998008
vt 0.001992 0.998008
vt 0.998008 0.001992
vt 0.001992 0.001992
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s 1
g pCube1
usemtl file1SG
f 1/1/1 2/2/2 3/3/3
f 3/3/3 2/2/2 4/4/4
s 2
f 3/13/5 4/14/6 5/15/7
f 5/15/7 4/14/6 6/16/8
s 3
f 5/21/9 6/22/10 7/23/11
f 7/23/11 6/22/10 8/24/12
s 4
f 7/17/13 8/18/14 1/19/15
f 1/19/15 8/18/14 2/20/16
s 5
f 2/5/17 8/6/18 4/7/19
f 4/7/19 8/6/18 6/8/20
s 6
f 7/9/21 1/10/22 5/11/23
f 5/11/23 1/10/22 3/12/24
不得不说,obj文件结构上非常简单,
v开头的行暗示是顶点数据,
v+' '的行表示是顶点数据之空间坐标(position),
v+'t'的行表示是顶点数据之纹理坐标(texture coordinate),
v+‘n’的行表示是顶点数据之法线向量(normal)。
上述文件为一个立方体,总共有8个顶点(v+' '开头的行正好是8行),而对于纹理坐标和法线,相同的顶点在不同三角面片上是不同的,在立方体中,一个顶点为三个面共有,所以纹理坐标和法线的描述应该有8*3=24行(v+'t',v+'n'开头的行正好各是24行)。
各个顶点的数据都有了,我们还需要索引数据。
对于我们通常写的3D程序来说,一个索引值对应于一个顶点,这个顶点有固定的空间坐标,纹理坐标,法线。
而对于obj文件,一个索引值对应于一个顶点数据的空间坐标,或者纹理坐标,法线,且由1开始计数。
比如说,对于上述的立方体obj文件,
v+' '的行从v+' '开始的第一行直到结束的第八行分别对应于索引1-8,
v+'t'的行从v+'t'开始的第一行直到结束的第二十四行分别对应于索引1-24,
v+'n'的行从v+'n'开始的第一行直到结束的第二十四行分别对应于索引1-24。
然后我们就像自助餐一样去自由组合“v+' '索引/v+'t'索引/v+'n'”索引,来得到需要的顶点。
再接着往下看,f开头的行,正如你所想,表示面(face),以3个“v+' '索引/v+'t'索引/v+'n'索引”描述的顶点组成。
对于其他信息,基本上都可以选择忽略,注意#开头的是注释。
知道了obj文件格式,就可以自由地转换到需要的格式了,比如下面这种非常简单的自定义格式:
Vertex Count: 36
Data:
-0.5 0.5 -0.5 0.001992 0.00199199 0 0 -1
0.5 -0.5 -0.5 0.998008 0.998008 0 0 -1
-0.5 -0.5 -0.5 0.001992 0.998008 0 0 -1
0.5 0.5 -0.5 0.998008 0.00199199 0 0 -1
0.5 -0.5 -0.5 0.998008 0.998008 0 0 -1
-0.5 0.5 -0.5 0.001992 0.00199199 0 0 -1
-0.5 0.5 0.5 0.001992 0.00199199 0 1 -0
0.5 0.5 -0.5 0.998008 0.998008 0 1 -0
-0.5 0.5 -0.5 0.001992 0.998008 0 1 -0
0.5 0.5 0.5 0.998008 0.00199199 0 1 -0
0.5 0.5 -0.5 0.998008 0.998008 0 1 -0
-0.5 0.5 0.5 0.001992 0.00199199 0 1 -0
-0.5 -0.5 0.5 0.998008 0.998008 0 0 1
0.5 0.5 0.5 0.001992 0.00199199 0 0 1
-0.5 0.5 0.5 0.998008 0.00199199 0 0 1
0.5 -0.5 0.5 0.001992 0.998008 0 0 1
0.5 0.5 0.5 0.001992 0.00199199 0 0 1
-0.5 -0.5 0.5 0.998008 0.998008 0 0 1
-0.5 -0.5 -0.5 0.001992 0.00199199 0 -1 -0
0.5 -0.5 0.5 0.998008 0.998008 0 -1 -0
-0.5 -0.5 0.5 0.001992 0.998008 0 -1 -0
0.5 -0.5 -0.5 0.998008 0.00199199 0 -1 -0
0.5 -0.5 0.5 0.998008 0.998008 0 -1 -0
-0.5 -0.5 -0.5 0.001992 0.00199199 0 -1 -0
0.5 0.5 -0.5 0.001992 0.00199199 1 0 -0
0.5 -0.5 0.5 0.998008 0.998008 1 0 -0
0.5 -0.5 -0.5 0.001992 0.998008 1 0 -0
0.5 0.5 0.5 0.998008 0.00199199 1 0 -0
0.5 -0.5 0.5 0.998008 0.998008 1 0 -0
0.5 0.5 -0.5 0.001992 0.00199199 1 0 -0
-0.5 0.5 0.5 0.001992 0.00199199 -1 0 -0
-0.5 -0.5 -0.5 0.998008 0.998008 -1 0 -0
-0.5 -0.5 0.5 0.001992 0.998008 -1 0 -0
-0.5 0.5 -0.5 0.998008 0.00199199 -1 0 -0
-0.5 -0.5 -0.5 0.998008 0.998008 -1 0 -0
-0.5 0.5 0.5 0.001992 0.00199199 -1 0 -0
提供顶点个数,然后Data下的每三行描述一个三角面片,没有使用索引。
每行从左到右是position(x,y,z),texcoord(u,v), normal(nx, ny, nz)。
为什么要自定义模型格式?这是因为各种建模软件的模型格式种类太多,而你可以对需要用的格式定制解析到你自定义的格式的Parser。由于都转为自定义格式供DirectX调用,在移植给OpenGL,Vulcan使用时也省了.x文件再转.xx文件的苦恼。
如何将obj文件转换到上述自定义格式见下面链接提供的ObjParser源代码。
最后感谢RasterTek提供的教程。
链接:http://pan.baidu.com/s/1pLpjUjT
// csdn传了经常被删= =,试试网盘。。
// github:https://github.com/DrinkMoon/directx11-pratices/tree/master/Engine/ObjParser
// = =个人练习directx11的repo而已。。欢迎吐槽。。
使用方式:
错误提示见parse-error-log.txt( 一些IO成功失败的信息,成功解析obj以后,也可在此文件中看到Successed in parsing mayaCube.obj这样的提示 )
示意图: