//作者:迷途的小书童

//微信公众号: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的作用。

       Cesium之b3dm格式_编程语言        

接下来就是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内部的一些数据对我们上述的理解进行验证