作者:yuezang - iTyran
3DS MAX通常的保存格式有*.max(现在生成的版本的格式),*.3ds(低版本的3ds Max生成的格式),*.ASC(ASC File Explorer),*.ASE(ASCII Scene Explorer),*.OBJ等文件格式。其他的软件保存的格式也是不尽相同的,同样的,这些软件和格式在保存数据方面也是各有各的不同。为了通用,我们选择比较通用的OBJ格式来作为讲解的例子,如果其他格式大家有需要的话,可以自己去研究数据保存的格式,至于读取的方式都是大同小异的。
1. 从3DS Max中导出OBJ文件
首先,咱们打开3DS Max并且随便创建一个模型,比如下面这个(简单的有点简陋了……)
画完以后,将文件导出为.obj格式,注意这里说的是导出,如果是选保存的话是找不到.obj格式的。导出的步骤是:
1) 打开“文件”菜单,选中里面的“导出”选项;
2) 在“导出”对话框中选择“Wavefront Object(*.OBJ)”,输入文件名后选“保存”,这里比如“test.obj”;
3) 在点击“保存”以后会弹出一个名叫“对象导出器”对话框,一般按下面这样选就可以了,其中要注意的就是“面”选项中要选择“Triangles”选项,这样的话将选择三角形作为基本图元;
4) 点击“确定”后打开“导出MTL”对话框,这个对话框是用来设置和OBJ文件配合使用的.MTL文件的,MTL文件主要用来保存材质信息,一般按下面的样子勾选就可以了;
5) 点击“确定”后生成了两个文件分别为“test.obj”和“test.mtl”。
2. OBJ文件格式分析
直接用记事本或者其他文本编辑工具打开test.obj文件,在开头可以看到这样的一些字符串:
# Max2Obj Version 4.0 Mar 10th, 2001
#
mtllib ./test.mtl
g
# object (null) to come ...
#
这里要注意的是在.obj文件中”#”号是作为注释符的(类似于bash等脚本)。Mtlib语句声明了引用的mtl文件的相对路径。接下来的行中得字符”g”在obj文件中表示的是组。
再往下看可以看到类似的内容
v 7.268521 0.000000 -2.808495
v 43.775921 3.692307 -11.804825
v 40.087490 4.896347 -20.872227
……
vt 0.500000 0.000000 0.000000
vt 0.750000 0.000000 1.000000
vt 0.791667 0.000000 1.000000
……
vn 0.061305 -0.985877 -0.155850
vn 0.176545 -2.839121 -0.448815
vn 0.176545 -2.839120 -0.448815
……
g (null)
s 1
f 1/1/1 3/3/3 2/2/2
f 1/1/1 4/4/4 3/3/3
f 1/1/1 5/5/5 4/4/4
……
从上面可以看出一般的obj文件中数据的格式是这样的:
前缀 参数1 参数2 参数3 …
前缀标识了这一行所存储的信息类型。参数则是具体的数据。OBJ文件数据类型的前缀一般有:
- v 表示本行指定一个顶点。 此前缀后跟着3个单精度浮点数,分别表示该定点的X、Y、Z坐标值
- vt 表示本行指定一个纹理坐标。此前缀后跟着两个单精度浮点数。分别表示此纹理坐标的U、V值
- vn 表示本行指定一个法线向量。此前缀后跟着3个单精度浮点数,分别表示该法向量的X、Y、Z坐标值
- f 表示本行指定一个表面(Face)。一个表面实际上就是一个三角形图元。
其他的一些不重要的信息可以查看附录。其中的参数v、vt、vn都是比较好理解的。
在解释以f为前缀的行的格式之前,我们不得不提一个新的概念,这就是顶点索引(Vertex Indices)。我们知道,对于每一个三角形,都需要用3个顶点来表示。例如在上面的立方体模型中,一共有6×2×3=36个顶点。仔细想想就会知道,在这36个顶点中,又相当数量的顶点是重合的。如果把这些重合的顶点都一一表示出来,就太浪费存储空间了。于是,我们提出了顶点索引的想法,解决空间占用问题。顶点索引的思想是建立两个数组,一个数组用于存储模型中所有的顶点坐标值,另一个数组则存储每一个表面所对应的三个顶点在第一个数组中的索引。下图显示了这种一一对应的关系。
以此类推,我们可以为模型中所有的法线、纹理坐标都建立起相应的索引,以节省更多的空间。而事实上,OBJ文件就是这么做的。接下来可以看看f类型的数据。f类型的数据一般有以下几种格式:
- f 1 2 3
- f 1/3 2/5 3/4
- f 1/3/4 2/5/6 3/4/2
第一种类型表示以顶点1,2,3作为索引建立三角形;
第二种类型表示以顶点1,2,3作为索引建立三角形,并且顶点1的纹理坐标为3,第二个顶点的纹理坐标为5,第三个顶点的纹理坐标为4;
第三种类型表示以顶点1,2,3作为索引建立三角形,并且顶点1的纹理坐标为3,法理坐标为4,第二个顶点的纹理坐标为5,法理坐标为6,第三个顶点的纹理坐标为4,法理坐标为2。
3. MTL文件格式分析
MTL文件与OBJ文件极其相似。只是用于标识行的前缀有所不同。这些前缀的意义如下表所示:
前缀 说明
- newmtl 表示新建一个材质。此前缀后跟一个字符串,表示此材质的名称。 此行之后的信息都是对这个材质进行设定。
- Ka 指定最后建立的材质的环境光成分。此行包含3个单精度浮点参数。
- Kd 指定最后建立的材质的漫射光成分。此行包含3个单精度浮点参数。
- Ks 指定最后建立的材质的镜面光成分。此行包含3个单精度浮点参数。
- map_Kd 指定最后建立的材质的反射贴图。如果此行的第一个参数为字符串”-s”,则此行将包括5个参数。其中第二、第三和第四个参数为此纹理贴图在U、V、W方向的缩放值,第五个参数为纹理图片的文件名。如果第一个字符串不是”-s”,那么第一个参数就是此纹理图片的文件名。
- map_Ks 指定最后建立的材质的镜面贴图。如果此行的第一个参数为字符串”-s”,则此行将包括5个参数。其中第二、第三和第四个参数为此纹理贴图在U、V、W方向的缩放值,第五个参数为纹理图片的文件名。如果第一个字符串不是”-s”,那么第一个参数就是此纹理图片的文件名。
根据这些信息,我们就可以在Opengl ES中实现obj和mtl文件的读取并显示了。至于代码实现和分析,下一篇文章中将会细细道来。
附录1 OBJ文件中所有数据类型
顶点数据(Vertex data):
v 几何体顶点(Geometric vertices)
vt 贴图坐标点(Texture vertices)
vn 顶点法线(Vertex normals)
vp 参数空格顶点 (Parameter space vertices)
*形态曲线(Free-form curve)/表面属性(surface attributes):
deg 度(Degree)
bmat 基础矩阵(Basis matrix)
step 步尺寸(Step size)
cstype 曲线或表面类型 (Curve or surface type)
元素(Elements):
p 点(Point)
l 线(Line)
f 面(Face)
curv 曲线(Curve)
curv2 2D曲线(2D curve)
surf 表面(Surface)
*形态曲线(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)
*形态表面之间的连接(Connectivity between free-form surfaces):
con 连接 (Connect)
成组(Grouping):
g 组名称(Group name)
s 光滑组(Smoothing group)
mg 合并组(Merging group)
o 对象名称(Object name)
显示(Display)/渲染属性(render attributes):
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)
参考的文章
1. 3D中的OBJ文件格式详解
2. 使用3D模型