glTF 2.0 格式详解
glTF 全称 GL Transmission Format,是由现有 OpenGL 的维护组织 Khronos 推出的一种 3D 数据传输格式,常用于 WebGL 和 OpenGL。
格式简介
格式特性
- 紧凑的文件大小。glTF JSON 文件本身是明文,紧凑且解析速度快,其他大型数据(如几何和动画)都存储在二进制文件中。
- 快速加载。glTF 的数据结构非常接近 GPU API,减少解析时间。
- 运行时独立性。glTF 不依赖任何 3D 引擎,不指定渲染和动画以外的运行时行为。
- 完整的 3D 场景表示。对于许多应用程序来说,从建模包中导出单个对象是不够的。通常,作者希望将整个场景(包括节点、变换、变换层次、网格、材质、相机和动画)加载到他们的应用程序中。glTF 努力保留所有这些信息以供下游应用程序使用。
- 可扩展性。虽然最初的基础规范支持丰富的功能集,但仍有许多增长和改进的机会。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 | "asset": { |
buffers & bufferViews
二进制数据和索引视图,如下,通过 uri 指明 buffer[0] -> ./scene.bin,然后再 bufferView 中通过 offset 和 length 去索引 buffer 数据。
1 | "buffers": [ |
scene & scenes
scene 表明默认加载的场景,下面的结构表示默认会加载定义在 scenes[0] 的场景。场景是由 nodes 节点构成,节点是树状结构,如下则会加载根节点为 nodes[0] 的节点。
1 | "scene": 0, |
nodes
节点和层次结构。节点类似图层的概念,可以包含 mesh 或应用平移 (translation)、旋转 (rotation)、缩放 (scale) 或任意矩阵变换 (matrix),如下图,nodes[0] 包含子节点 nodes[1],并且应用了旋转变换,这里旋转用四元数表示。而 nodes[1] 包含了 meshes[0] 的网格数据。
1 | "nodes": [ |
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 | "meshes": [ |
accessors
访问器。是 glTF 特有的访问数据的结构,它关联了 bufferView 声明的数据切片,指明了数据类型,同时也附带了额外信息,如 min、max、count 等。
1 | "accessors": [ |
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 | "materials": [ |
textures & images
贴图。texture 对象的 source 和 sampler 关联了图片(images) 和采样器(samplers) 的索引。images 通过 uri 关联外部图片文件。
1 | "textures": [ |
samplers
采样器。描述了纹理映射的方式。其参数 magFilter、minFilter、wrapS、wrapT 都是枚举类型。
1 | "samplers": [ |
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 官方文档