前置知识:GLB文件格式解析GLTF文件格式解析 (baidu.com)
glb格式解析 | 码农家园 (codenong.com)
3D性能优化 | 说一说glTF文件压缩 - 知乎 (zhihu.com)
glTF格式详解(目录) - 知乎 (zhihu.com)
{
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 3575,
"type": "VEC2",
"max": [
0.9999003,
-0.0221377648
],
"min": [
0.0006585993,
-0.996773958
]
},
{
"bufferView": 1,
"componentType": 5126,
"count": 3575,
"type": "VEC3",
"max": [
1.0,
1.0,
0.9999782
],
"min": [
-1.0,
-1.0,
-0.9980823
]
},
{
"bufferView": 2,
"componentType": 5126,
"count": 3575,
"type": "VEC4",
"max": [
1.0,
0.9999976,
1.0,
1.0
],
"min": [
-0.9991289,
-0.999907851,
-1.0,
1.0
]
},
{
"bufferView": 3,
"componentType": 5126,
"count": 3575,
"type": "VEC3",
"max": [
0.009921154,
0.00977163,
0.0100762453
],
"min": [
-0.009921154,
-0.00977163,
-0.0100762453
]
},
{
"bufferView": 4,
"componentType": 5123,
"count": 18108,
"type": "SCALAR",
"max": [
3574
],
"min": [
0
]
}
],
"asset": {
"generator": "glTF Tools for Unity",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 28600
},
{
"buffer": 0,
"byteOffset": 28600,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 71500,
"byteLength": 57200
},
{
"buffer": 0,
"byteOffset": 128700,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 171600,
"byteLength": 36216
}
],
"buffers": [
{
"uri": "BoomBox.bin",
"byteLength": 207816
}
],
"images": [
{
"uri": "BoomBox_baseColor.png"
},
{
"uri": "BoomBox_occlusionRoughnessMetallic.png"
},
{
"uri": "BoomBox_normal.png"
},
{
"uri": "BoomBox_emissive.png"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"TEXCOORD_0": 0,
"NORMAL": 1,
"TANGENT": 2,
"POSITION": 3
},
"indices": 4,
"material": 0
}
],
"name": "BoomBox"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
},
"normalTexture": {
"index": 2
},
"occlusionTexture": {
"index": 1
},
"emissiveFactor": [
1.0,
1.0,
1.0
],
"emissiveTexture": {
"index": 3
},
"name": "BoomBox_Mat"
}
],
"nodes": [
{
"mesh": 0,
"name": "BoomBox"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"source": 0
},
{
"source": 1
},
{
"source": 2
},
{
"source": 3
}
]
}
bufferViews":有好几个,为什么每个都设置 "buffer": 0, 这个“buffer”指的啥???
GLTF格式用于描述3D模型和场景的信息。
在您提供的JSON示例中,
`buffers`,`bufferViews`和`accessors`协同工作以描述3D模型的顶点和其他数据。
### Buffers
- **Buffers** 是存储实际的二进制数据的地方。在这个例子中,
`"uri": "BoomBox.bin"` 指明了buffer的位置,
`"byteLength": 207816` 描述了buffer的长度。
```json
"buffers": [
{
"uri": "BoomBox.bin",
"byteLength": 207816
}
]
```
### BufferViews
- **BufferViews** 描述了如何从buffer中查看数据。
每个`bufferView`有一个`byteOffset`来描述从buffer的哪个位置开始,
以及`byteLength`来描述view的长度。`"buffer": 0` 指明了该`bufferView`
是从第一个(也是唯一一个)buffer中查看的。
```json
"bufferViews": [
{
"buffer": 0,
"byteLength": 28600
},
...
]
```
### Accessors
- **Accessors** 则进一步描述了如何从`bufferView`中解读数据。
它会定义component的类型,例如,是否是一个VEC3或者SCALAR,
以及数据的类型,例如,是否是FLOAT。它还会包含一些有关数据的其他信息,例如min和max值。
```json
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 3575,
"type": "VEC2",
...
},
...
]
```
### 为什么每个 BufferView 的 `"buffer": 0` ?
在您的JSON示例中,所有的`bufferViews`都有`"buffer": 0`,
这是因为所有的`bufferViews`都是从同一个buffer中提取的,
也就是上述`buffers`数组中的第一个(并且是唯一的)buffer。
如果您的GLTF文件中有多个buffer,那么您将会看到不同的`bufferViews`
关联到不同的buffer。例如,如果有一个`bufferView`从第二个buffer中
提取数据,那么它将会有`"buffer": 1`。
"accessors": [ { "bufferView": 0, "componentType": 5126, "count": 3575, "type": "VEC2", ... }, ... ]
这accessors中的每一个bufferView可以重复吗,比如accessors三个孩子,bufferView分别为0,1,1???
比如这种文件
{"asset":{"generator":"COLLADA2GLTF","version":"2.0"},"scene":0,"scenes":[{"nodes":[0]}],"nodes":[{"children":[1],"matrix":[1.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0]},{"mesh":0}],"meshes":[{
"primitives":[{"attributes":{"NORMAL":1,"POSITION":2},"indices":0,"mode":4,"material":0}],"name":"Mesh"}],
"accessors":[
{"bufferView":0,"byteOffset":0,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":24,"max":[1.0,1.0,1.0],"min":[-1.0,-1.0,-1.0],"type":"VEC3"},{"bufferView":1,"byteOffset":288,"componentType":5126,"count":24,"max":[0.5,0.5,0.5],"min":[-0.5,-0.5,-0.5],"type":"VEC3"}]
,"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[0.800000011920929,0.0,0.0,1.0],"metallicFactor":0.0},"name":"Red"}],
"bufferViews":[
{"buffer":0,"byteOffset":576,"byteLength":72,"target":34963},
{"buffer":0,"byteOffset":0,"byteLength":576,"byteStride":12,"target":34962}],
"buffers":[{"byteLength":648}]}
是的,`accessors`中的`bufferView`可以重复。每个`accessor`定义了
如何解读存储在`bufferView`中的数据。不同的`accessor`可以使用相同
的`bufferView`,但可能会有不同的`byteOffset`、`componentType`、
`count`或`type`,以便以不同的方式解读相同的数据,或解读该`bufferView`
中的不同部分数据。
举个例子,假设我们有两个`accessor`,它们都指向`bufferView` 1,但
一个是解读VEC3类型数据,另一个是解读SCALAR类型数据。那么,这两个
`accessor`将会从相同的`bufferView`中提取不同类型和格式的数据。
```json
"accessors": [
{
"bufferView": 1,
"componentType": 5126,
"count": 1000,
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5123,
"count": 2000,
"type": "SCALAR"
}
]
```
在这个例子中,即便两个`accessor`都引用了`bufferView` 1,但由于
它们有不同的`type`和`componentType`,它们将会以不同的方式解读
`bufferView`中的数据。
glTF T ? JSON{
"asset": {
"version": "2.0",
"generator": "draco_decoder"
},
"scenes": [
{
"nodes": [
0
]
}
],
"scene": 0,
"nodes": [
{
"children": [
1
],
"matrix": [
1,
0,
0,
0,
0,
0,
-1,
0,
0,
1,
0,
0,
0,
0,
0,
1
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1
},
"indices": 0,
"mode": 4,
"material": 0,
"extensions": {
"KHR_draco_mesh_compression": {
"bufferView": 0,
"attributes": {
"NORMAL": 0,
"POSITION": 1
}
}
}
}
]
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0,
0,
1
],
"metallicFactor": 0,
"roughnessFactor": 1
},
"emissiveFactor": [
0,
0,
0
],
"alphaMode": "OPAQUE"
}
],
"accessors": [
{
"componentType": 5121,
"count": 36,
"normalized": false,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 152
}
],
"buffers": [
{
"byteLength": 152
}
],
"extensionsRequired": [
"KHR_draco_mesh_compression"
],
"extensionsUsed": [
"KHR_draco_mesh_compression"
]
}
? BIN DRACO
??鱑?喊﹤ ???鏌?I)?皷 ? ? ? ? €?
这段 JSON 是 glTF(GL Transmission Format)格式的,一个用于
3D 场景和模型的传输格式。这个例子中使用了 Draco 压缩,这是一
种几何图形压缩方法,可以大幅减小 3D 模型的文件大小。
以下是该 JSON 文件的组织结构:
1. **asset**
- 描述了 glTF 资源的信息,比如版本和生成器。
2. **scenes**
- 定义了 3D 场景的列表,其中包含了场景所包含的节点(nodes)。
3. **scene**
- 表示当前要展示的场景。
4. **nodes**
- 定义了场景中的节点列表,其中每个节点可能包含子节点、网格、变换矩阵等。
5. **meshes**
- 定义了网格的列表。每个网格都包含了一组 primitive,每个 primitive
都有自己的 attributes,如位置、法线等。
6. **materials**
- 定义了场景中使用的材料的属性。
7. **accessors**
- 定义了如何从 bufferView 中访问数据,包含了类型、数量等信息。
8. **bufferViews**
- 定义了如何在 buffer 中访问原始二进制数据。
9. **buffers**
- 存储了原始二进制数据的长度信息。
10. **extensionsRequired 和 extensionsUsed**
- 定义了此 glTF 模型所需和所用的扩展,本例中使用了 Draco 压缩的扩展。
### Draco 压缩
在这个例子中,`"KHR_draco_mesh_compression"` 扩展被使用,表示模型数据经
过了 Draco 压缩。压缩后的数据存储在 `buffer` 中。Draco 压缩的具体信息是
在每个 `primitive` 的 `extensions` 字段中定义的:
```json
"extensions": {
"KHR_draco_mesh_compression": {
"bufferView": 0,
"attributes": {
"NORMAL": 0,
"POSITION": 1
}
}
}
```
这里的 `bufferView` 指向包含压缩数据的 `bufferView`,而 `attributes` 定义
了属性类型和对应的索引,这些索引对应于 Draco 压缩数据中的属性。
总而言之,这个 JSON 文件定义了一个 glTF 场景,其中包含了节点、网格、材料、访
问器、缓冲视图和缓冲器,以及 Draco 压缩的扩展,以减小 3D 模型的文件大小。 若
要渲染这个 3D 模型,需要按照定义在访问器和缓冲视图中的信息,从缓冲中获取原始
数据,然后解压 Draco 压缩的数据,最后应用材料并将其放入场景中。
indices是怎么来的,我看其他glb文件有的是1,有的是2???
在 glTF 结构中,`primitives`字段定义了如何将顶点属性组合成几何图元。
每个`primitive`都包含一个`attributes`对象,`attributes`对象定义了
一组`accessor`,这些`accessor`引用了包含实际几何数据的缓冲区视图
(`bufferView`)。`indices`字段则是一个指向`accessor`的索引,这个
`accessor`包含了组成这些几何图元的索引。
- `"indices": 0`表示用来组成几何图元的索引存储在`accessors`数组的第一个元素中。
- `"indices": 1`表示索引存储在`accessors`数组的第二个元素中。
- `"indices": 2`表示索引存储在`accessors`数组的第三个元素中。
以此类推。这个`indices`引用的`accessor`定义了如何从`attributes`指定的
顶点属性中索引值,来组成三角形或其他几何图元。
例如,如果您有以下几何结构:
```
"accessors": [
{ ... }, // 0: indices
{ ... }, // 1: POSITION
{ ... } // 2: NORMAL
],
"primitives": [
{
"attributes": {
"POSITION": 1,
"NORMAL": 2
},
"indices": 0,
}
]
```
在这个例子中,`indices`是`0`,意味着`accessors`数组的第一个元素包含了
组成几何图元的索引。而`POSITION`和`NORMAL`属性分别由`accessors`数组的
第二个和第三个元素提供。
所以,如果您在不同的glTF或glb文件中看到不同的`indices`值,这仅仅是因为
这些索引存储在`accessors`数组中不同的位置。这并不会影响最终模型的几何
结构,因为`indices`和`attributes`的组合提供了完整的几何定义。