加载3D模型的时候,遇到.obj格式的模型文件。之前有专门看过相关的资料,可惜没有总结,一下就忘了。再次用到,又去搜索了一番,发现网上很多文章讲的不是很全面。于是就找到百科上的文档,总结一下。
Obj(或者.obj)是一种几何定义文件格式,第一次是 Wavefront Technologies在他们的可视化加强动画包里面使用的。文件格式是公开的,并能很好的在其他的3D应用中被支持。
Obj文件格式是一种简单的单独表示3D几何图元的文件格式——也就是,顶点的坐标,每个顶点纹理的UV坐标,顶点法向量,以及组成多边形的面的顶点坐标、以及纹理UV坐标序列。面的顶点默认为逆时针顺序,法向量不是必须的。OBJ文件并非归一化的,但是可以在注释中加入缩放信息。
Obj文件可以是ASCII的编码(.obj)方式也可以是二进制格式(.mod)。以ASCII格式存储的obj文件必须用.obj作为文件拓展名。
1. 文件格式(File Format)
以哈希字符(#)开始的一行表示注释。
# this is a comment
一个obj格式的文件可能包含了顶点数据,自由形式的曲面/表面属性,绘制索引序列,自由形式的曲面/表面内容声明,关联自由形式的表面,组和渲染属性信息。大多数常见的绘制索引表现为几何顶点,纹理坐标,顶点法线以及多边形的面:
# List of geometric vertices, with (x,y,z[,w]) coordinates, w is optional and defaults to 1.0.
v 0.123 0.234 0.345 1.0
v ...
...
# List of texture coordinates, in (u, v [,w]) coordinates, these will vary between 0 and 1, w is optional and defaults to 0.
vt 0.500 1 [0]
vt ...
...
# List of vertex normals in (x,y,z) form; normals might not be unit vectors.
vn 0.707 0.000 0.707
vn ...
...
# Parameter space vertices in ( u [,v] [,w] ) form; free form geometry statement ( see below )
vp 0.310000 3.210000 2.100000
vp ...
...
# Polygonal face element (see below)
f 1 2 3
f 3/1 4/2 5/3
f 6/4/1 3/5/3 7/6/5
f 7//1 8//2 9//3
f ...
...
1.1 几何顶点
一个顶点可以用字符v开头的一行来表示。接着后面跟上(x, y, z [w])的值来表示顶点坐标。W是可选项,默认为1.0。一些应用支持顶点颜色,通过在x y z后面跟上red, green, blue值来表示。颜色值的范围为0到1.0。
1.2 参数顶点空间
自由形式的几何图元声明可以使用字符vp开头的行来表示,用于定义一个曲面或者平面的参数空间中的顶点。"u"只能在曲面顶点中使用,u和v用于表示non-rational剪裁曲面的点,而u,v以及w表示rational剪裁曲面的点。
1.3 表面单元
表面通过一个包含顶点,纹理以及法线索引的序列来表示。类似四边形这种多边形可以通过多于三个包含顶点/纹理/法线索引来定义。
OBJ文件也支持自由形式的使用曲面和表现来定义对象的几何图元,例如NURBS表面。
顶点索引
一个合法的顶点索引符合上面定义的顶点序列格式。如果一个索引是正值则表示相对于顶点序列从1开始的偏移。如果一个索引是负的,表示从顶点序列结尾的偏移,从-1开始。
每个面都可以包含三个或者更多的顶点。
f v1 v2 v3 ....
纹理坐标索引
在描述一个平面的时候,纹理坐标索引作为可选项用于描述该顶点相关的纹理坐标。为了描述纹理坐标索引,必须在顶点坐标索引之后紧密添加一根斜线(/),之后再紧密添加纹理坐标索引。在斜线的前后都不能有空格。一个合法的纹理坐标索引从1开始,并符合之前描述的格式。每个面可以包含三个或者更多的单元。
f v1/vt1 v2/vt2 v3/vt3 ...
顶点法线索引
法线索引用于描述顶点的法向量,在描述面的时候是可选项。要添加顶点法线索引,必须在纹理索引之后添加第二根斜线(/),然后在之后添加法线索引。斜线前后不能有空格。合法的法线索引从1开始,并符合之前面描述的格式。每个面可以包含三个或者更多的单元。
f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
顶点坐标法线索引(不包含纹理索引)
可以在定义几何图元的时候忽略纹理坐标索引,但是必须在顶点坐标索引后加上两根斜线(//),然后添加法线索引。
f v1//vn1 v2//vn2 v3//vn3 ...
其他几何格式
Obj文件采用若干差值方法来支持高阶表面,例如泰勒和B差值,尽管支持这些特性要使用一些非标准的第三方文件。Obj文件不支持网格分级或者任何其他形式的动画或形变,例如顶点蒙皮或纹理变形。
材质引用
描述多边形的可见属性存储在外部的.mtl文件中。OBJ文件可能会引用超过一个的.mtl文件。.mtl文件可能包含一个或者多个不同命名的材质定义。
mtllib [external .mtl file name]
...
通过绘制单元之后的这个标签来指明使用的材质。材质名称必须和外部定义的.mtl文件名称匹配。
usemtl [material name]
...
objects名称和多边形group标签
o [object name]
...
g [group name]
...
- Group声明用于组织模型的单元(element)以及简化数据操作
- Object声明用于标识在一个文件中的不同object单元
所有的group声明都是基于状态的。依旧是一旦声明了group,将应用于所有之后的内容,直到下一个group 声明。
通过Smoothing Group可以实现多边形平滑渲染。
s 1
...
# Smooth shading can be disabled as well.
s off
...
单个obj文件中可以包含多个object标签或group标签。
其中,o标签和g标签仅仅是在组织上进行分组而存在的,例如一个o标签下,可能包含多个g,或者一个g开头的顶点数据集合之后包含多个g组织描述的三角面。也有将usemtl标签作为网格分组的,原因是考虑了同一组网格使用了相同的纹理。但有个不方面的地方就是对于需要单个控制的地方,略显不便。例如一个o或者g标签的数据集合表示人脸,之后眼睛,耳朵,鼻子等五官分作不同的g来组织,使用同一个纹理。采用usemtl分组的话,如果想对眼睛,嘴巴,等进行单独变换的时候很不方便。因此,本人还是采用g来进行网格划分。
通常处理obj文件的时候,会抛弃顶点法线数据,而通过顶点信息来进行计算。有了以上的顶点坐标、法线、纹理坐标等信息,就可以进行3D模型文件的渲染了。
下面是一个简单3D模型的光照效果。猛戳代码