携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情。
glTF 数据加载流程可大致理解成如下的过程:
scenes->nodes->meshes->primitives(POSITION、NORMAL、TANGENT、TEXCOORD_0、materials、textures、images)->accessors->bufferViews->buffers
截取一段 gltf 的数据,我们可以看到它整体是一个object,里面有很多 key : value 的数据项。
我们按照模型加载的顺序来梳理一下这份数据的组成。
1. scene
首先通过"scene": 0 访问 "scenes" 值中的第 1 个元素(数组下表为 0 的元素),如下所示:
一般模型只有一个也是默认场景,如果是多个,则根据对应的scene字段确定哪一个是默认场景。一个scene都包含一个nodes字段,指定了scene的根结点。
2. node
本例中 nodes 对应的值为 0,代表根节点为nodes字段下对应的第 1 个元素(数组下表为 0 的元素),如下图所示。
该节点的具体内容在 nodes 对应的数组里的第2个元素(数组下表为 1 的元素)mesh
3. mesh
根据mesh里的值 0,在meshes数据中找到对应的第 1 个元素。
4. primitive
可以看到网格中都是使用 Primitive(基元) 组织的,Primitive 是 glTF 数据规范中最小的图形单位,这里定义了构成当前这个基元的一些属性(顶点POSITION、顶点法线NORMAL、uv坐标TEXCOORD_0、TANGENT),面索引indices。
5. accessor
基元中顶点定义由其下的 attributes 对象下 POSITION 属性来寻找访问器(Accessor),从而获取到数据,也就是说顶点数据需要根据POSITION后面的值,这里是 2 ,通过accessors 访问其数组内的第3个元素(数组下表为 2 的元素),如下图中的绿色箭头所示,
访问器是链接bufferView和mesh之间的桥梁。accessors 指定了数据存在了哪个 bufferView中,在当前这块bufferView中的其实位置的字节偏移byteOffset,当前字段的数据的每个component的类型componentType,数据格式type,比如float、int;比如SCALAR、VEC3;属性的数量count;最大最小值max,min。
6. bufferView
bufferView 对应的值指定了其在 bufferViews 中的位置,下图中 bufferView 值1 表示其是bufferViews中的第2个元素(数组下表为 1 的元素)
7. buffer
根据 bufferViews 中的 buffer 下标 0,找到buffers 数组中的第1个元素(数组下表为 10的元素),这里只有一个元素。需要注意的是,这里要考虑 POSITION 的数据是第2块bufferView(bufferView = 1)中的对应的数据的byteOffset=288的位置,这块数据在buffers数组中的第一个元素Box.bin中,综上顶点数据在bin文件288字节开始处一直到bytelength=576的位置。
8. 总体加载流程示意图
想必有了上面的基础,对于一些未包含到的细节我们都可以粗略地从这张图上理清他们的加载关系。