Obj格式是一种开源的模型文件规范,可以被以纯文本标记的形式表示。

以下通过Blender创建一个简单的Obj格式模型,我们可以通过其来一窥构成一个三维模型所需要的数据信息。

Obj文件

# Blender 3.5.1
# www.blender.org
mtllib block.mtl
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.875000 0.500000
vt 0.625000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
vt 0.625000 0.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.125000 0.750000
s 0
usemtl Material
f 1/1/1 5/5/1 7/9/1 3/3/1
f 4/4/2 3/3/2 7/10/2 8/12/2
f 8/13/3 7/11/3 5/6/3 6/8/3
f 6/7/4 2/2/4 4/4/4 8/14/4
f 2/2/5 1/1/5 3/3/5 4/4/5
f 6/8/6 5/6/6 1/1/6 2/2/6

这其中可以看到包含了大量的的数据,我们逐条进行分析:

注释

# Blender 3.5.1
# www.blender.org

该标记为注释,由于该模型由Blender导出,因此Blender在其中留下了该信息。

材质库链接

mtllib block.mtl

mtllib标记意为Material Library,表示对材质文件的链接,其中block.mtl是被链接的材质文件的相对路径。

关于材质的解释,我们会在下文中再详细讨论。

网格体

o Cube

o标记意为Object,表示一个网格体对象的起始,而Cube表示该网格体对象的名称。

一个Obj格式模型中可以包含多个网格体,每个网格体可以理解为是一个独立的物体,不同的网格体之间可以共用信息,但不会有任何点、线、面相互连接。

在下一个o标记开始之前的所有数据都属于当前标记所指向的网格体对象。

顶点

v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000

v标记意为Vertex,表示一个顶点,顶点即为三维世界中的一个点,而其后的数据分别代表该顶点的x/y/z轴坐标。

法向量

vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000

vn标记意为Vertex Normal,表示顶点的法向量。并且该数据是一个单位向量,长度始终为1,仅用来指导方向。

法向量表示垂直于平面的直线。

为什么顶点需要法向量?

实际上,法向量是在后续用于将点构成面时使用的。

为什么顶点和法向量的数量对不上?

法向量用于面中,且由于有些面的法向量可能相同,这些面可以通过索引来使用相同的法向量,从而节省存储空间。

例如下图为我们使用到的立方体模型:

这个立方体的有六个四边面,每个面使用一个法向量。

纹理坐标

vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.875000 0.500000
vt 0.625000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
vt 0.625000 0.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.125000 0.750000

vt意为Vertex Texture Coodinates,表示顶点的纹理坐标,纹理坐标即我们常说的UV坐标。

顶点的纹理坐标是一个二维向量,每个坐标对应纹理图像上的一个点。

因为纹理通常是一张二维图像,我们常常将U理解为纵轴,而V理解为水平轴。

纹理是覆盖在面上的图像,能够为面赋予一些复杂的图案。

下图为我们使用到的立方体的UV展开图,可以发现其中的坐标点与Obj模型中的14个UV坐标点是一一对应的。

image-uvsb.png

平滑组

s 0

s意为Smoothing Group,标记一个平滑组的起始,直到下一个s标记的起始或者下一个o标记的起始而结束。0为该顶点组的组号。

平滑组用来指示面之间是否平滑显示,即处于同一平滑组内的面之间的如阴影的连接将被平滑过渡,而如果面未处于同一个平滑组,则其连接处的阴影等信息可能被重新计算。如下图所示:

其中可以看到一个较为突兀的阴影处,该处实际上与其他部分不在同一个平滑组,因此该位置的阴影信息被重新计算了。

需要指出的是,在Blender中,可能无法直接找到标记平滑组的功能,因为该功能被划分到了标记锐边当中。

材质

usemtl Material

usemtl意为Use Material,标记下列面使用的材质。

关于材质的解释,我们会在下文中再详细讨论。

f 1/1/1 5/5/1 7/9/1 3/3/1
f 4/4/2 3/3/2 7/10/2 8/12/2
f 8/13/3 7/11/3 5/6/3 6/8/3
f 6/7/4 2/2/4 4/4/4 8/14/4
f 2/2/5 1/1/5 3/3/5 4/4/5
f 6/8/6 5/6/6 1/1/6 2/2/6

f意为Face,即为面。每个标记表示一个面,此处由于我们的模型是一个立方体,因此这组数据表示了6个四边面。

可以注意到,每个面中又包含了4组数据。实际上,其中每组数据表示顶点/纹理坐标/法向量对应的索引。

例如 1/1/1 该数据表示第一个顶点 v 1.000000 1.000000 -1.000000 第一个纹理坐标 vt 0.625000 0.500000 和第一个法向量 vn -0.0000 1.0000 -0.0000

Mtl文件

Mtl意为Material,一般翻译为材质/材料,Mtl文件可以理解为材质库,能够存储Obj文件所需要的材质信息。

材质已在上文中被多次指出,此处我们终于可以解释材质的含义:

材质实际上包含了一系列渲染中用到的参数,三维软件运用这些参数可以将面/模型渲染出对应的效果。

与上文中使用到的立方体模型链接的材质文件内容如下所示:

# Blender 3.5.1 MTL File: 'None'
# www.blender.org

newmtl Material
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

笔者目前对这些参数暂无详细的理解,因此此处只做简单介绍。

注释

# Blender 3.5.1 MTL File: 'None'
# www.blender.org

与上文中相似,此处也包含了一些Blender预设的注释信息。

声明新材质

newmtl Material

newmtl意为New Material,即为此行开始声明新材质的标记。其后的Material是该材质的名称。

镜面反射指数

Ns意为Specular,表示镜面反射指数。

环境光反射

Ka意为Ambient,表示环境光反射。

漫反射

Kd意为Diffuse,表示漫反射。

镜面反射

Ks意为Specular,表示镜面反射。

参考资料

https://paulbourke.net/dataformats/obj/

https://paulbourke.net/dataformats/mtl/