3d-tiles
3d-tiles
参考资料
- https://github.com/CesiumGS/3d-tiles
- https://blog.csdn.net/qq_31709249/article/details/102643371
- https://zhuanlan.zhihu.com/p/350265716
正篇
3D Tiles
3D Tiles是用于流式传输大规模异构3D地理空间数据集的开放规范。为了扩展Cesium的地形和图像流,3D Tiles将用于流式传输3D内容,包括建筑物,树木,点云和矢量数据。
3D Tiles 在glTF的基础上,加入了分层HLOD的概念(可以把3D Tiles简单地理解为带有H LOD 的 glTF ),3D Tiles和二维地图中的瓦片组织非常相似,它定义了一种数据分层结构和一组切片格式,用于渲染数据内容。瓦片被组织在一个树中,它结合了层次细节级别 (HLOD) 的概念,以实现空间数据的最佳渲染。每个图块都有一个边界体积,一个定义空间范围的对象,完全包围其内容。树具有空间连贯性;子图块的内容完全在父图块的边界体积内。3D Tiles 没有为数据的可视化定义明确的规则,客户可以按照自己合适的方式来可视化 3D 空间数据。同时,3D Tiles 也是 OGC 标准规范成员之一,可用于在台式机、Web端和移动应用程序中实现与海量异构3D地理空间数据的共享、可视化、融合以及交互功能。
Tileset—瓦片集
通常,一个3D Tiles 数据会使用一个主 tileset JSON 文件作为定义 tileset 的入口点,一般是以 tileset.json 文件命名(当然该文件名称可以修改)。tileset JSON 至少包含三个顶级属性:asset、geometricError、root。下面是一个tileset.json文件的例子:
1 | { |
1)asset
asset包含整个tileSet的元数据对象。asset.Version属性,用于定义3D Tiles版本,该版本指定tileset的JSON模式和基本的tileset格式。tileVersion属性可选,用于定义特定的应用程序的tileset。
2)properties
properties是一个对象,包含tileset中每个feature属性的对象。上面的例子是一个建筑物的3DTiles,因此每个瓦片都含有三维建筑物模型,每个三维建筑物模型都有高度属性,所以上面的例子中就定义了Height属性。属性中每个对象的名称与每个要素属性的名称相对应(如例子中的Height对应高度),并且包含该属性的最大值和最小值,这些值用于创建样式的颜色渐变非常有用。
3)geometricError
geometricError是一个非负数,是通过这个几何误差的值来计算屏幕误差,确定Tileset是否渲染。如果在渲染的过程中,当前屏幕误差大于这里定义的屏幕误差,这个Tileset就不渲染。即根据屏幕误差来控制Tileset中的root是否渲染。
4)root
root 是一个 JSON 对象,定义了最根级的 Tile ,它存储的是真正的Tile 。也就是说,root 的数据组织方式与 Tile 的数据组织方式是一样的。
需要注意的是,root.geometricError 与 tileset 的顶级 geometricError 不同,tileSet的geometricError是根据屏幕误差来控制tileSet中的root是否渲染,而root(tile)中的geometricError则是用来控制tile中的children是否渲染。
root.children 是一个定义子 Tile 的对象数组,每个Tile还会有其children,这样就形成了一种递归定义的树状结构。每个子 Tile 的内容完全由其父 Tile 的boundingVolume 包围,并且通常是其 geometricError 小于其父 Tile 的 geometricError,因为越接近叶子节点,模型越精细,与原模型的几何误差就越小。对于叶子节点的 Tile ,其数组的长度为零,或者是未定义 children 。
当然,为了创建树状结构,tile 的 content.uri 也可以指向外部的 tileset(另一个 tileset 的 JSON 文件)。这样做的一个好处就是,不同的tileset可以分开存储,例如我国的每个城市可单独存储成一个tileset,然后再定义一个包含所有 tileset 的全局 tileset。
Tiles—瓦片
瓦片包含用于确定是否渲染瓦片的元数据、对渲染内容的引用以及任何子瓦片的数组。切片实际上也是一个JSON对象,它由以下属性组成。
1)boundingVolumes(边界范围框)
定义了瓦片的最小边界范围,用于确定在运行时渲染哪个瓦片,有region、box、sphere三种形式。
2)geometricError(几何误差)
是一个非负数,以米为单位定义了不同瓦片层级的几何误差,通过几何误差来计算以像素为单位的屏幕误差(SSE),从而确定不同缩放级别下应该调用哪个层级的瓦片。简单来说,Tile的几何误差是用来确定瓦片切换层级的,即控制LOD的。
3)refine(细化方式)
确定瓦片从低级别(LOD)切换为高级别(LOD)的呈现过程,简单来说就是瓦片是如何切换的,其中包括替换(REPLACE)和添加(ADD)两种方式。替换就是直接把父级的瓦片替换掉,添加则是在父级瓦片的基础增加细节部分。
理论上来说,ADD方式是一种非常好的方式,是一种增量的LOD策略,能够减少数据的传输。这里强调一下,refine属性在根节点的Tile中是必须定义的,子节点中是可选的。如果子节点没有定义,则继承父节点的该属性。
4)content(内容)
content属性指定了瓦片实际渲染的内容。content.uri属性可以是一个指定二进制块(b3dm、i3dm、pnts、cmpt)的位置,也可以是指向另一个外部的tileset.json。
content.boundingVolume属性定义了类似 Tile属性boundingVolume的边界范围框,但是content.boundingVolume是一个紧密贴合的边界范围框,仅包含切片的内容。该属性可以用来做视锥体裁剪,只渲染视图范围内的内容,如果该属性没定义,系统也会自动计算。下图是关于Tile.boundingVolumes和content.boundingVolumes 的比较,红色是Tile的boundingVolumes,包围了Tileset的整个区域;蓝色是content的boundingVolumes,仅包围切片中的渲染模型。
5)children(孩子节点)
这个很容易理解,因为3D Tiles是分级别的,所以每个Tile还会有子Tile、子子Tile、子子子Tile …,分的越多,层级划分的越精细,和下面讲到的Tileset瓦片集root.children是同一个概念。
6)viewerRequestVolume(可选,观察者请求体)
定义了一个边界范围,使用与boundingVolumes相同的模式,只有当观察者处于其定义的范围内时,Tile才显示,从而精细控制了个别瓦片的显示与否。如下图所示,只有相机拉近到某一个距离时,才显示屋内的球。
7)transform(可选,位置变换矩阵)
定义了一个4x4的变换矩阵 ,通过此属性,Tile的坐标就可以是自己的局部坐标系内的坐标,最后通过自己的transform矩阵变换到父节点的坐标系中。它会对Tile的content、boudingVolume、viewerRequestVolume进行转换。详情可查看3D Tiles的规范文档。
Tile 数据格式
格式 | 用途 |
---|---|
批量3D模型(b3dm) | 大型异构3D模型,包括三维建筑物、地形等 |
实例3D模型(i3dm) | 3D模型实例,如树、风力发电机等 |
点云(pnts) | 点云 |
组合数据(cmpt) | 以上不同格式的切片组合到一个切片中 |