glTF 2.0 格式详解

glTF 2.0 格式详解

glTF 全称 GL Transmission Format,是由现有 OpenGL 的维护组织 Khronos 推出的一种 3D 数据传输格式,常用于 WebGL 和 OpenGL。

格式简介

格式特性

  1. 紧凑的文件大小。glTF JSON 文件本身是明文,紧凑且解析速度快,其他大型数据(如几何和动画)都存储在二进制文件中。
  2. 快速加载。glTF 的数据结构非常接近 GPU API,减少解析时间。
  3. 运行时独立性。glTF 不依赖任何 3D 引擎,不指定渲染和动画以外的运行时行为。
  4. 完整的 3D 场景表示。对于许多应用程序来说,从建模包中导出单个对象是不够的。通常,作者希望将整个场景(包括节点、变换、变换层次、网格、材质、相机和动画)加载到他们的应用程序中。glTF 努力保留所有这些信息以供下游应用程序使用。
  5. 可扩展性。虽然最初的基础规范支持丰富的功能集,但仍有许多增长和改进的机会。glTF 定义了一种机制,允许添加通用扩展。

与其他 3D 格式对比

mesh 材质 骨骼 动画 场景信息
STL
OBJ
FBX
glTF

1.0 与 2.0 版本的区别

最主要的改动是 1.0 使用 glsl 去描述材质,而 2.0 使用了更加通用的 PBR 材质。

格式解析

glTF 由 JSON 文件、bin 文件和其他外部数据(如图片等)组成,JSON 文件的根节点属性见下图:

数据类型 描述
accessors accessor [1-*] An array of accessors.
animations animation [1-*] An array of keyframe animations.
asset object Metadata about the glTF asset.
buffers buffer [1-*] An array of buffers.
bufferViews bufferView [1-*] An array of bufferViews.
cameras camera [1-*] An array of cameras.
images image [1-*] An array of images.
materials material [1-*] An array of materials.
meshes mesh [1-*] An array of meshes.
nodes node [1-*] An array of nodes.
samplers sampler [1-*] An array of samplers.
scene integer The index of the default scene.
scenes scene [1-*] An array of scenes.
skins skin [1-*] An array of skins.
textures texture [1-*] An array of textures.
extensions object Dictionary object with extension-specific objects.
extras any Application-specific data.

asset

顶级必须包含 asset 属性,其中必须包含 version 指明 glTF 的版本,还可包含如下的其他附加信息。

1
2
3
4
5
6
7
8
9
10
"asset": {
"extras": {
"author": "EdwinRC (https://sketchfab.com/Edwin3D)",
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
"source": "https://sketchfab.com/3d-models/low-poly-winter-scene-2ffe1ed449414cc184078dd1e2882284",
"title": "Low Poly Winter Scene"
},
"generator": "Sketchfab-4.86.2",
"version": "2.0"
}

buffers & bufferViews

二进制数据和索引视图,如下,通过 uri 指明 buffer[0] -> ./scene.bin,然后再 bufferView 中通过 offset 和 length 去索引 buffer 数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"buffers": [
{
"byteLength": 8570184,
"uri": "scene.bin"
}
],
"bufferViews": [
{
"buffer": 0,
"byteLength": 792612,
"byteOffset": 0,
"name": "floatBufferViews",
"target": 34963
},
// ...
]

scene & scenes

scene 表明默认加载的场景,下面的结构表示默认会加载定义在 scenes[0] 的场景。场景是由 nodes 节点构成,节点是树状结构,如下则会加载根节点为 nodes[0] 的节点。

1
2
3
4
5
6
7
"scene": 0,
"scenes": [
{
"name": "OSG_Scene",
"nodes": [0]
}
]

nodes

节点和层次结构。节点类似图层的概念,可以包含 mesh 或应用平移 (translation)、旋转 (rotation)、缩放 (scale) 或任意矩阵变换 (matrix),如下图,nodes[0] 包含子节点 nodes[1],并且应用了旋转变换,这里旋转用四元数表示。而 nodes[1] 包含了 meshes[0] 的网格数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"nodes": [
{
"children": [
1
],
"name": "RootNode (gltf orientation matrix)",
"rotation": [
-0.70710678118654746,
-0,
-0,
0.70710678118654757
]
},
{
"mesh": 0,
"name": "Cylinder.008_0"
},
// ...
]

meshes

网格数据是模型最重要的部分,如下所示,meshes[0] 是一个 Cylinder.008_0 的圆柱体网格。 attributes 的数据会直接传入 vertex shader,它们的含义如下:

  • POSITION 顶点坐标
  • NORMAL 法向量
  • TANGENT 切向量
  • COLOR_0 顶点颜色
  • TEXCOORD_0 贴图UV,可以看出 glTF 支持多组 UV

它们的值是 accessor 的索引,最终会取到 bufferView -> buffer 中的数据。例如 POSITION 应该是 XYZ 坐标的数组,TEXCOORD_0 应该 UV 坐标的数组。

mode 和 indices 涉及到图元装配,mode 是枚举类型,与 WebGL 中定义的一致:

类型 取值
POINTS 0
LINES 1
LINE_LOOP 2
LINE_STRIP 3
TRIANGLES 4
TRIANGLE_STRIP 5
TRIANGLE_FAN 6

所以这里 indices 为三角形 mesh 顶点的索引数组,数据也是通过 accessor 索引。
material 是材质的索引,存放在 materials[0]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"meshes": [
{
"name": "Cylinder.008_0",
"primitives": [
{
"attributes": {
"COLOR_0": 3,
"NORMAL": 1,
"POSITION": 0,
"TANGENT": 2,
"TEXCOORD_0": 4
},
"indices": 5,
"material": 0,
"mode": 4
}
]
},
// ...
]

accessors

访问器。是 glTF 特有的访问数据的结构,它关联了 bufferView 声明的数据切片,指明了数据类型,同时也附带了额外信息,如 min、max、count 等。

1
2
3
4
5
6
7
8
9
10
11
"accessors": [
{
"bufferView": 2,
"componentType": 5126,
"count": 25327,
"max": [15.562509536743164, -45.877700805664062, 30.865560531616211],
"min": [-31.794599533081055, -90.910537719726562, -38.811481475830078],
"type": "VEC3"
}
// ...
]

type

类型 含义 元素数量
SCALAR 标量 1
VEC2 元向量,常用于描述 uv 2
VEC3 3元向量,常用于描述 xyz 坐标或 rgb 颜色 3
VEC4 4元向量,常用于描述四元数或 rgba 颜色 4
MAT2 2阶矩阵 4
MAT3 3阶矩阵 9
MAT4 4阶矩阵 16

materials

材质。glTF 2.0 支持了 PBR 材质,PBR (Physically Based Rendering) 的含义是基于物理正确的方式来计算灯光与材质,也就是说 PBR 材质的渲染基于物理引擎而非渲染器。目前 PBR 材质已经被各种图形引擎和建模软件所支持,是一种通用的材质规范,因此也非常符合 glTF 的理念。具体 PBR 相关概念可以参考这篇文章 Physically Based Rendering and Lighting

下面的例子定义了一个 PBR 材质,首先 doubleSided 表明了它是双面渲染的,然后 baseColorFactor 定义了它的基本颜色是 rgba(1, 1, 1, 1) 的白色,baseColorTexture 定义了贴图的索引和 uv,metallicFactor 描述了金属性,roughnessFactor 描述了粗糙程度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"materials": [
{
"doubleSided": true,
"name": "Main",
"pbrMetallicRoughness": {
"baseColorFactor": [
1,
1,
1,
1
],
"baseColorTexture": {
"index": 0,
"texCoord": 0
},
"metallicFactor": 0,
"roughnessFactor": 0.6
}
}

textures & images

贴图。texture 对象的 source 和 sampler 关联了图片(images) 和采样器(samplers) 的索引。images 通过 uri 关联外部图片文件。

1
2
3
4
5
6
7
8
9
10
11
"textures": [
{
"sampler": 0,
"source": 0
}
],
"images": [
{
"uri": "textures/Main_baseColor.png"
}
]

samplers

采样器。描述了纹理映射的方式。其参数 magFilter、minFilter、wrapS、wrapT 都是枚举类型。

1
2
3
4
5
6
7
8
"samplers": [
{
"magFilter": 9729,
"minFilter": 9987,
"wrapS": 10497,
"wrapT": 10497
}
]

magFilter

拉伸纹理,表示三角面大而纹理小的情况,取值如下

类型 取值 含义
NEAREST 9728 取临近点的颜色,对应 GL_NEAREST
LINEAR 9729 线性插值,对应 GL_LINEAR

minFilter

压缩纹理,表示三角面小而纹理大的情况,增加 mipmap 的情况,概念和上面类似,取值如下

类型 取值
NEAREST 9728
LINEAR 9729
NEAREST_MIPMAP_NEAREST 9984
LINEAR_MIPMAP_NEAREST 9985
NEAREST_MIPMAP_LINEA 9986
LINEAR_MIPMAP_LINEAR 9987

wrapS

横轴 wrap mode

类型 取值 示例
CLAMP_TO_EDGE 33071
MIRRORED_REPEAT 33648
REPEAT 10497

wrapT

纵轴 wrap mode,取值同 wrapS

最后总结

最后附一张官方给出的 glTF 格式的属性节点关系图,便于理清各个节点的映射关系,如果还有细节的地方不明白,可以参考 glTF 2.0 官方文档

Posted on

2021-09-23

Updated on

2021-10-19

Licensed under

Comments