五一之前第二次在工作中遇到了需要自主生成3dtiles以在cesium中显示3d模型的需求,这一次在实现这个需求时发现之前对3dtiles格式的理解有很多不到之处,趁着端午节假期把这些理解记录下来以备之后再次需要时查看。
这篇文章并没有完全说明3dtiles文件的所有组织方式,只解析类似gltf格式的b3dm文件格式,其中多有不到之处,如不能解决您的问题,请多包涵。
我在学习的过程中主要参考了这几个地方:
1.b3dm组织方式:https://zhuanlan.zhihu.com/p/158994083
2.gltf组织方式:https://zhuanlan.zhihu.com/p/65735191
3.3dtiles github文档:https://link.zhihu.com/?target=https%3A//github.com/CesiumGS/3d-tiles/tree/master/specification/TileFormats/Batched3DModel%23binary-gltf
目录
一、一个3Dtiles文件夹内都包括什么
二、.json文件内容
三、b3dm文件的组织方式
3.1 b3dm组织方式
3.2 注意!!!!
四、结语
一、一个3Dtiles文件夹内都包括什么
一个3dtiles文件包括一个组织文件(.json)和数个瓦片文件(.i3dm/.b3dm/.pnts/.cmpt)
组织文件是3dtiles的入口,其中记录了每个瓦片的范围、各条属性的极值、每个瓦片的显示范围等整体信息;瓦片文件则记录具体要显示的模型信息。
二、.json文件内容
.json文件就是一个正常的JSON文件,只是其中的内容需要按照制定好的规则填写
详细的.json文件规则可以参考这里:https://github.com/CesiumGS/3d-tiles/tree/main/specification
这里只通过一个可用的例子展示几个关键的内容。
{
/* asset属性中记录版权信息、版本信息、垂直轴等信息*/
"asset": {
"gltfUpAxis": "Z",
"version": "1.0"
},
/* geometricError是几何误差,这个我不太理解,和显示细节有关,要求是是非负且由父到子递减*/
"geometricError": [
1000000
],
/* properties是模型各个属性的最大最小值,规定必须只能记录最大值和最小值,这样支持3dtiles的引擎才能正确获取这个属性*/
"properties": {
"I": {
"minimum": 3.0,
"maximum": 179.0
},
"J": {
"minimum": 5.0,
"maximum": 184.0
}
},
/* root是3dtile树状结构的根节点*/
"root": {
/* 转换矩阵,这样写相当于没转换,这个没接触过的话可以搜索坐标变换(还有很多领域有这个,其实都是一个事)*/
"transform": [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
],
/* 同上*/
"geometricError": 10000,
/* 当子节点加载时和父节点的关系,ADD是叠加,REPLACE是替换*/
"refine": "ADD",
/* 子节点,可以镶套*/
"children": [
{
"boundingVolume": {
"box": [
-2294502.3282544096,
3706199.5334441354,
4644166.925639546,
263.23593662912026,
0,
0,
0,
176.47964480728842,
0,
0,
0,
166.596532296855
]
},
"geometricError": 1000,
/* 该节点的瓦片文件*/
"content": {
"uri": "./1.b3dm"
}
}
],
/* 根节点的要素范围,有三种设置方式,这里的box是记录中心点和三个轴方向的半距*/
"boundingVolume": {
"box": [
-2302317.288889875,
3706793.65386175,
4639561.535310894,
8965.85696362378,
0,
0,
0,
5891.165495929075,
0,
0,
0,
6173.917311145924
]
}
}
}
三、b3dm文件的组织方式
最上面关于b3dm的文章已经写的非常好了,这里我按照自己的方式尝试讲的更具象一些,并单独说明一些稍微难理解的地方。
b3dm实质上是由数个二进制信息体拼接而成,下面用字符串展示出具体内容,实际使用时要存储为对应数据格式的二进制体。
3.1 b3dm内容
先是文件头,固定长度为28byte
然后是要素表,再是要素表数据体,瓦片类型为b3dm的3dtiles不需要要素表来储存其属性名信息,故要素表可以固定为以下两种,要素表数据体为空。
"{"BATCH_LENGTH":XXXX}"
或
"{"BATCH_LENGTH":XXXX,"RTC_CENTER":[XXX,XXX,XXX]}"
BATCH_LENGTH为这个b3dm中单体化要素的个数
RTC_CENTER为这个b3dm的中心点,如果设置了这个属性,则后面glb里的坐标都会加上这个中心
值得一提的是由于3dtiles里的数字最多只能识别16位有效数字,因此需要尽可能多的保留小数点后的信息时,可以把中心点整数部分放在这里,这样后面glb里每个坐标小数点前的位数能减少一些,小数点后能保存的信息也就多一些。
然后是批量表,再是批量表数据体,这两个部分要对应着填写
批量表
"{"filed1":{"byteOffset":0,"componetType":FLOAT,"type":SCALAR},"filed2":{"byteOffset":12,"componetType":FLOAT,"type":SCALAR}}"
其中field1和field2是属性名,也就是身高、年龄之类的,
byteOffset是这个属性是在后面数据体的什么位置开始
componetType是这个属性的类型,有固定的名称得参考官方的github文档,链接在上面
type可以简单理解为就三类:SCALAR(一个数)VEC2(两个数)VEC3(三个数),如果这三类满足不了你的需求,还有MAT2、MAT3等,这个和gltf的type是一致的,可以查阅gltf格式文档
批量表数据体
"111222"
每个属性的具体数据,个数需要和前面要素表里BATCH_LENGTH保持一致,例如前面要素表是"{"BATCH_LENGTH":3}",那1,1,1就是上面批量表中filed1的值,至于这三个值是如何和后面glb里要素对应上的,要讲到glb时才能明了。
这时上面byteOffset的意思也能解释了,可以看到filed1的类型是FLOAT,FLOAT是4个字节长度,BATCH_LENGTH又是3,则第四个数开始是filed2吗,需要从头跳过12个字节开始读,因此field2的byteOffset是12
最后是glb,这部分和glb文件的内容几乎完全一致,只是多了batchID这个属性,原glb文件内容很多,这里就不展开了,有需要的话还请参阅glb格式文档,或者之后单独写一个gltf和glb的说明,这里就只说明batchID要怎么添加以及有什么用处
{
'asset': {
'generator': '给我一块奥利奥吧',
'version': '2.0'
},
'scene': 0,
'scenes': [
{
'nodes': [
0
]
}
],
'nodes': [
{
'matrix': [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
],
'mesh': 0
}
],
'meshes': [
{
'primitives': [
{
'attributes': {
'POSITION': 0,
'NORMAL': 1,
'_BATCHID': 2
},
'material': 0,
'mode': 4
}
]
}
],
'materials': [
{
'pbrMetallicRoughness': {
'metallicFactor': 0
},
'name': 'Material'
}
],
'accessors': [
{
'bufferView': 0,
'byteOffset': 0,
'componentType': 5126,
'count': 312,
'min': [
-2294765.5641910387,
3706023.0537993284,
4644000.329107248
],
'max': [
-2294239.0923177805,
3706376.013088943,
4644333.522171842
],
'type': 'VEC3'
},
{
'bufferView': 1,
'byteOffset': 0,
'componentType': 5126,
'count': 312,
'max': [
1,
1,
1
],
'min': [
-1,
-1,
-1
],
'type': 'VEC3'
},
{
'bufferView': 2,
'byteOffset': 0,
'componentType': 5126,
'count': 312,
'max': [
1
],
'min': [
0
],
'type': 'SCALAR'
}
],
'bufferViews': [
{
'buffer': 0,
'byteLength': 3744,
'byteOffset': 0,
'target': 34962
},
{
'buffer': 0,
'byteLength': 3744,
'byteOffset': 3744,
'target': 34962
},
{
'buffer': 0,
'byteLength': 1248,
'byteOffset': 7488,
'target': 34962
}
],
'buffers': [
{
'byteLength': 8736
}
]
}
下面这段解释需要了解gltf格式才能看懂:
也就是说在普通的glb基础上新增一个bufferview,这个bufferview在meshes中叫_BATCHID,这个BATCHID从0开始,每有一个三角面就需要写入一个BATCHID,这个BATCHID意味着在取值时从批量表数据体里取第几个数据。
至此,一个完整的b3dm文件就构建好了
3.2 注意!!!!
“
二进制数据体,无论是要素表、批量表,首个字节相对于b3dm文件的字节偏移量,必须是8的倍数,结束字节的字节偏移量,也必须是8的倍数。
如果不满足,可以填充空白字节满足此要求。
特别的,二进制数据体中,每一个属性值的第一个数值的第一个字节的偏移量,相对于整个b3dm文件,必须是其 componentType
的倍数,如果不满足,则必须用空白字节填满。
”
也就是说,在生成要素表、要素表数据体、批量表、批量表数据体时,如果他们的二进制长度不是8的倍数,要在后面补充空格直到他们的长度为8的倍数。文章来源:https://www.toymoban.com/news/detail-795994.html
四、结语
3dtiles能实现的内容还有很多很多,我自己也只是刚刚了解了这一点,如果这篇文章的内容不能帮助到您,再次请您见谅。文章来源地址https://www.toymoban.com/news/detail-795994.html
到了这里,关于基于b3dm的3Dtiles文件组织方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!