基于b3dm的3Dtiles文件组织方式

       五一之前第二次在工作中遇到了需要自主生成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的倍数。

四、结语

        3dtiles能实现的内容还有很多很多,我自己也只是刚刚了解了这一点,如果这篇文章的内容不能帮助到您,再次请您见谅。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Cesium B3DM文件是一种用于三维地球可视化的开放格式文件,用于存储建筑物、地形、植被等元素的3D模型和纹理。然而,由于其中包含了大量的几何数据和纹理信息,所以Cesium B3DM文件往往会比较大。 造成Cesium B3DM文件过大的原因有以下几点: 1. 几何数据:Cesium B3DM文件中存储了建筑物、地形等物体的几何信息,包括顶点坐标、法线、纹理坐标等。这些数据量庞大,尤其是对于复杂的建筑物或大范围的地形,会导致文件大小增加。 2. 纹理信息:Cesium B3DM文件中还包含了贴图信息,用于给模型上色或添加纹理。纹理图像的像素数目和颜色深度决定了文件的大小。有时候高分辨率的纹理图像会导致文件变得非常庞大。 3. 数据冗余:在一些情况下,Cesium B3DM文件可能包含了冗余的数据,比如重复的顶点坐标或纹理坐标。这些冗余数据会占据额外的存储空间,使文件变大。 为了解决Cesium B3DM文件过大的问题,可以采取一些优化措施: 1. 减少细节:对于一些不太重要的细节,可以进行简化,例如减少建筑物的边角或细小物体的数量。这样可以有效地减少几何数据量,从而减小文件大小。 2. 压缩数据:可以采用专业的数据压缩算法对文件进行压缩,减少文件大小。常用的压缩算法包括LZ77、DEFLATE等。 3. 使用纹理压缩:可以采用纹理压缩算法,例如基于GPU的纹理压缩技术,将纹理图像进行压缩,进一步减小文件体积。 对于Cesium B3DM文件太大的问题,我们可以通过上述措施来进行优化。这样不仅可以减小文件大小,提高加载速度,还可以减少网络传输和存储成本。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值