FBX 格式几乎受到所有 3D 引擎的支持,是 Autodesk 开发的 3D 模型的专有格式。它支持顶点、索引、法线、UV坐标、材质和动画。
FBX还支持许多其他类型的信息,但它们对游戏引擎几乎没有用处。
推荐:用 NSDT编辑器 快速搭建可编程3D场景
有两种可行的方法可以将 FBX 文件支持集成到引擎中:
- 使用 Autodesk 官方的 FBX SDK,它允许导入和导出 FBX 文件或具有相同用途的其他库。 SDK 公开了两个接口,一个是 C++ 接口,另一个是 Python 接口。
- 编写自定义 FBX 解析器,避免对其他库的依赖。
第一种方法很简单:只需下载 SDK 并按照文档进行操作即可。 请注意,FBX SDK 的使用并不像人们想象的那么简单。
我将在本文中介绍 FBX 文件的结构。 对它的理解允许我们编写一个自定义的、轻量级的解析器。 有关自定义 FBX 解析器的示例,你可以查找 Blender 的 FBX 导入器/导出器插件。
然而,由于该格式是专有的,因此该格式的公共规范不可用。 尽管如此,FBX SDK 仍包含一些标头,部分揭示了格式的布局。
格式可以是 ASCII(文本文件,人类可读)或二进制形式。
因此,从第一个表示更容易推断出格式的结构是什么,以及我们需要的信息(几何、材质等)在哪里。
首先,我将展示如何从 FBX ASCII 文件获取基本几何信息。 如果你在实际实现方面需要帮助(此处未涵盖),请随时询问我,我将尽最大努力通过伪代码甚至 C 语言帮助你。如果你解析FBX的目的是为了转换为其他格式,那么可以直接使用NSDT 3DConvert这个强大的 在线3D格式转换工具,支持FBX、GLTF、GLB、OBJ、DAE、STL、PLY等数十种3D格式:
1、FBX文件结构
这是一个 示例 FBX 文件。
首先要注意的是,有些行以分号开头:这些是注释,在读取文件时必须忽略。
在初始注释之后,找到了标识符 FBXHeaderExtension。 这是文件结构的第一个主节点。 FBX 文件格式确实是遵循以下方案的树结构:
每个节点或子节点都可以有自己的特定属性。 属性也可以在主节点之外找到,但通常可以忽略。 一般来说,节点的基本结构如下:
node name: eventual_properties { <---- beginning of node
Node_Property_1: value
Node_Property_2: value
Subnode1 : { <---- beginning of subnode
Subnode_Property_1: value
[…]
} <---- end of subnode
Node_Property_3: value
[…]
} <---- end of node
这是在示例文件中找到的一个节点(第一个):
FBXHeaderExtension: { <---- beginning of node
FBXHeaderVersion: 1003 <---- node property
FBXVersion: 6100
CreationTimeStamp: { <---- beginning of subnode (1)
Version: 1000 <---- subnode property
Year: 2014
Month: 03
Day: 20
Hour: 17
Minute: 38
Second: 29
Millisecond: 0
} <---- end of subnode (1)
Creator: "FBX SDK/FBX Plugins build 20070228"
OtherFlags: { <---- beginning of subnode (2)
FlagPLE: 0
} <---- end of subnode (2)
}
理解结构是编写高效解析器的基础。
在第一个节点中,我们找到两个属性(FBXHeaderVersion 和 FBXVersion),其值是格式版本。 在本例中为 6.1 版本。 其他信息可以忽略,除非还想读取创建日期 (CreationTimeStamp)。
2、FBX对象节点
最重要的节点肯定是对象节点。
对象节点包含模型的顶点、索引、法线、UV 坐标和材质。 它的结构如下:
Objects: { <---- beginning of node Objects
Model: “model name”, “Mesh” { <---- beginning of node of the model
[…]
Vertices: […] <---- vertices
PolygonVertexIndex: […] <---- indices
LayerElementNormal: { } <---- node of the normals
LayerElementUV: { } <---- node of the UV coords
} <---- end of node of the model
Material: “material name”, “” { } <---- node of the material
[…]
} <---- end of node Objects
3、FBX顶点
正如我们所见,顶点可以在模型子节点的“Vertex”属性中找到。
语法如下:
Vertices: v1_x, v1_y, v1_z, v2_x, v2_y, v2_z, […]
每个顶点都有三个空间坐标 (x,y,z),用逗号分隔(也将一个顶点与另一个顶点分开)。 坐标显然是用十进制形式表示的,带有点。
示例如下:
Vertices: 0.000000,0.104800,39.291698,0.000000,0.043400,-44.424301,0.000000,38.654301,-41.818802,-0.000000,39.455002,44.424400
构成模型的顶点将是:
v1(0.000000,0.104800,39.291698)
v2(00.000000,0.043400,-44.424301)
v3(0.000000,38.654301,-41.818802)
v4(0.000000,39.455002,44.424400)
4、FBX多边形的顶点索引
索引可以在 PolygonVertexIndex 属性下找到。
FBX 文件可以导出三边多边形(三角形)或更多。 大多数文件导出四边形多边形(四边形)。 语法和顶点类似,但是有一点需要注意:
PolygonVertexIndex: i1, i2,-i3, i4, i5,-i6,[…] <—- triangles syntax
PolygonVertexIndex: i1, i2, i3, -i4, i5, i6, i7, -i8, […] <—- quads syntax
组成多边形的索引是按顺序排列的,负索引意味着它是多边形的最后一个索引。 该指数需要设为正数,然后你必须从中减去 1!
[如果你想知道为什么,那是因为原始索引与 -1 进行了异或。 例如索引 3 变为 -4]
示例如下:
PolygonVertexIndex: 8,7,3,-7,4,8,7,-3,0,5,8,-5
组成模型的多边形将是:
p1(8,7,3,6)
p2(4,8,7,2)
p3(0,5,8,4)
请注意表示多边形末端的索引已设为正数,然后从中减去 1。
提醒:显卡不喜欢四边形,因此在显示模型之前必须将每个具有四个边的多边形分成两个三角形。
5、FBX法线
法线可以在 Normals 属性的子节点 LayerElementNormal(它又是 Model 的子节点)下找到。 语法与其中一个顶点相同,即一系列 (x,y,z) 坐标。
Normals: n1_x, n1_y, n1_z, n2_x, n2_y, n2_z, […]
你需要注意 MappingInformationType 属性,它可以具有以下值:
- ByPolygon:按多边形处理,这意味着模型的每个多边形都有一个法线。
- ByPolygonVertex:按多边形顶点处理,这意味着模型的每个多边形的每个顶点都有一个法线。例如,如果模型有 8 个顶点组成四个四边形,则将有 16 个法线(1 个法线 * 4 个多边形 * 4 个多边形顶点)。 请注意,通常游戏引擎需要顶点仅定义一个法线。 因此,如果你发现一个顶点具有多个法线,可以忽略第一个法线之后找到的法线,或者计算所有法线的平均值(法线平滑)。
- ByVertex:按顶点处理,这意味着模型的每个顶点都有一个法线。有时也称为 ByVertice,如 Blender 导出器所写。我认为作者是西班牙人。
- ByEdge:按边处理,这意味着模型的每个边都有一个法线(罕见)
- AllSame:这意味着模型的每个顶点都有相同的法线,这对于大多数模型来说很少见或不可能。
另一个重要的属性是 ReferenceInformationType 属性,它可以具有以下值:
- Direct:表示法线是有序的。
- IndexToDirect(或旧版本 FBX 格式的索引):表示法线的顺序由 NormalsIndex 属性给出。
以下是一个可能比文字更清楚的图形示例。 示例模型是一个位于 X 轴和 Y 轴上的平面(因此所有顶点的 Z 坐标将为 0),由 9 个顶点和 4 个多边形(四边形)组成。 示例图是从顶部看到的平面视图。
6、FBX UV坐标
UV 坐标可以在 UV 属性中的子节点 LayerElementUV(它又是 Model 的子节点)下找到。 语法类似于顶点和法线的语法,但当然会有两个坐标而不是三个。
UV: u1, v1, u2, v2, […]
你仍然需要注意 MappingInformationType 和 ReferenceInformationType 属性! 这两个属性可以具有的值与法线的值相同,因此适用相同的规则。 索引属性(如果有,即定义了 IndexToDirect)是 UVIndex。
原文链接:FBX文件结构解读 — BimAnt