//作者:迷途的小书童
//微信公众号:g0415shenweri
b3dm格式
参考文档:
https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Batched3DModel/README.md
工具设计
计划写一个工具来查看B3dm的格式,顺便了解其原理。主要分为两部分,一部分是对属性参数的解析,一部分是对gltf的解析。
网址一:https://github.com/daniel-hilton/gltf-b3dm-convertor
实现gltf-b3dm-convertor的互相转换。
这个库无法使用,而且缺少问题
网址二:https://github.com/CesiumGS/3d-tiles-validator
这里的工具可以验证自己导出的3dtiles的格式是否正确
网址三:https://github.com/KhronosGroup/glTF-Validator
这个工具可以验证gltf的格式是否正确
网址四:https://github.com/CesiumGS/3d-tiles-validator/tree/master/samples-generator
这个工具可以自动生成3dtiles格式
发现一个同行,有不少研究心得
由于有了这些轮子,基本上不需要再自己设计了,我们只需要加工即可。
B3dm格式验证
文件名:lib\validateB3dm.js
B3dm例子解读
这里推荐一个json格式化的工具:
https://www.bejson.com/explore/index_new/0
featureTableJson:
{
"BATCH_LENGTH": 10,
"RTC_CENTER": [
1214914.5525041146,
-4736388.031625768,
4081548.0407588882
]
}
- BATCH_LENGTH:模型的个数,即这个B3dm的文件里面有10个模型
- RTC_CENTER:模型中心点的坐标,即下面所有模型的坐标都是以这个中心点为原点的坐标。
batchTableJson:
{
"id": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"Longitude": [
-1.3197004795898053,
-1.3197036065852055,
-1.319708772296242,
-1.3197052536661238,
-1.3197012996975566,
-1.3197180493677987,
-1.3197058762367364,
-1.3196853243969762,
-1.3196881546957797,
-1.3197161145487923
],
"Latitude": [
0.6988582109,
0.6988621128191176,
0.698870582386204,
0.6988575056044288,
0.6988603596248432,
0.6988530761634713,
0.6988687144359211,
0.6988698975892317,
0.6988569944876143,
0.6988651780819983
],
"Height": [
11.721514919772744,
12.778013898059726,
9.500697679817677,
8.181250356137753,
10.231159372255206,
12.68863015063107,
6.161747192963958,
7.122806219384074,
12.393268510699272,
11.431036269292235
]
}
这里的id、Longitude、Latitude和Height都拥有10个元素的数组,这里其实是和上面的BATCH_LENGTH为10是一一对应的。也就是说这个字符串保存的是每个模型对应的属性信息。
接下来我,我们来研究gltf的json如下:
"scenes": [
{
"nodes": [
0
]
}
]
scenes场景引用了nodes数组下标为0的对象。
"nodes": [
{
"matrix": [
1,
0,
0,
0,
0,
0,
-1,
0,
0,
1,
0,
0,
0,
0,
0,
1
],
"mesh": 0,
"name": "rootNode"
}
matrix是矩阵变换,这里的变化矩阵是为了使gltf的进行Z轴向上的翻转,具体参考官网介绍
https://github.com/CesiumGS/3d-tiles/blob/master/specification/README.md#gltf-transforms
nodes节点又引用了meshs数组下标为0的节点。
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"_BATCHID": 2
},
"indices": 3,
"material": 0,
"mode": 4
}
]
}
]
POSITION、NORMAL、_BATCHID、indices和material对于的值,都对于与accessors的数组的索引,mode表示网格体的类型,这里4表示是三角网。其他详细描述参考下面网址:
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0/#primitivemode
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "VEC3",
"min": [
-69.262685040012,
-63.42564369086176,
-51.21932876482606
],
"max": [
84.98775890329853,
61.14907375629991,
46.49423664715141
]
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "VEC3",
"min": [
-0.9686407230533828,
-0.7415693003175017,
-0.7655772493024053
],
"max": [
0.9686407230533828,
0.7415693003175017,
0.7655772493024053
]
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "SCALAR",
"min": [
0
],
"max": [
9
]
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5123,
"count": 360,
"type": "SCALAR",
"min": [
0
],
"max": [
239
]
}
]
accessors定义了4个bufferview。刚好和上面的索引可以对应上。我们研究第一个就可以了
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "VEC3",
"min": [
-69.262685040012,
-63.42564369086176,
-51.21932876482606
],
"max": [
84.98775890329853,
61.14907375629991,
46.49423664715141
]
}
- bufferView:引用了bufferviews数组的索引为0
- byteOffset:bufferviews数据偏移0字节
- componentType:5126 代表数值类型为float
- count:代表由240个vec3数据
- type:数据类型为三维向量 VEC3
- min:max:表示240个vec3的最小和最大值
"bufferViews": [
{
"buffer": 0,
"byteLength": 2880,
"byteOffset": 0,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteLength": 2880,
"byteOffset": 2880,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteLength": 960,
"byteOffset": 5760,
"target": 34962,
"byteStride": 4
},
{
"buffer": 0,
"byteLength": 720,
"byteOffset": 6720,
"target": 34963
}
]
bufferviews我们也研究第一个数据,如下:
具体可以参考下面网址:
https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md
{
"buffer": 0,
"byteLength": 2880,
"byteOffset": 0,
"target": 34962,
"byteStride": 12
}
buffer:引用buffer数组索引的为0
byteLength:字节的长度
byteOffset:buffer数据偏移0个字节开始
target:34962, 表示 ARRAY_BUFFER 表示这个数据是顶点属性,另外还可以表示顶点索引 通34963
byteStride:表示每个元素实际上占用12个字节,可以通过下图有个直观的了解byteStride的作用。
接下来就是buffer了
"buffers": [
{
"name": "buffer",
"byteLength": 7440
}
]
这里buffer为7440大小保存了上面所有引用的数据。
完整的json格式如下:
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "VEC3",
"min": [
-69.262685040012,
-63.42564369086176,
-51.21932876482606
],
"max": [
84.98775890329853,
61.14907375629991,
46.49423664715141
]
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "VEC3",
"min": [
-0.9686407230533828,
-0.7415693003175017,
-0.7655772493024053
],
"max": [
0.9686407230533828,
0.7415693003175017,
0.7655772493024053
]
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 240,
"type": "SCALAR",
"min": [
0
],
"max": [
9
]
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5123,
"count": 360,
"type": "SCALAR",
"min": [
0
],
"max": [
239
]
}
],
"asset": {
"generator": "3d-tiles-samples-generator",
"version": "2.0"
},
"buffers": [
{
"name": "buffer",
"byteLength": 7440
}
],
"bufferViews": [
{
"buffer": 0,
"byteLength": 2880,
"byteOffset": 0,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteLength": 2880,
"byteOffset": 2880,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteLength": 960,
"byteOffset": 5760,
"target": 34962,
"byteStride": 4
},
{
"buffer": 0,
"byteLength": 720,
"byteOffset": 6720,
"target": 34963
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
1,
1,
1,
1
],
"roughnessFactor": 1,
"metallicFactor": 0
},
"alphaMode": "OPAQUE",
"doubleSided": false,
"emissiveFactor": [
0,
0,
0
]
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"_BATCHID": 2
},
"indices": 3,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"matrix": [
1,
0,
0,
0,
0,
0,
-1,
0,
0,
1,
0,
0,
0,
0,
0,
1
],
"mesh": 0,
"name": "rootNode"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
]
}
buffer数据获取
这里决定取出buffer内部的一些数据对我们上述的理解进行验证