3dtile概述

434 阅读4分钟

导言

五一假期闲来无事,想起最近在看3dtile的相关资料,遂写一篇文章记录,如有错误希望各位朋友帮忙指正,这里万分感谢。

如果你是一名gis开发者,用过cesium之类的gis框架,那么应该对于3dtile这种数据格式并不陌生。它是你在web端展示大规模三维数据最好的帮手。

概述

3dtile是一个开放的规范,用于跨桌面、web和移动应用程序进行共享、可视化、融合、交互和分析大量异构的3D地理空间内容,其建立在gltf上。

上文是官方给的关于3dtile的定义,从中我们可以提取四个关键词,一即大规模,二即跨平台,三即glTF,四即地理空间内容。

其中第一,第二无需多赘述,第三gltf是3D模型和场景高效流媒体和渲染的开放标准,而3d地理空间内容可以是由倾斜测量产生的倾斜摄影数据,也可以是激光雷达扫描而来的点云数据,大规模的通用模型数据(gltf,fbx之类)。

一个3dtile的瓦片可以由上述的地理空间内容进行肆意的组合。也就是说,你可以在一个3dtile里即展示倾斜摄影,也展示点云,还可以展示你自己手工建立的模型。

3dtile将你的模型数据,以树状结构组织,一般树的划分是以kd-tree或者oc-tree或者bvh-tree的形式划分。 以下是一个tielset的结构,它被描述为了一个json。

{
 "asset": { ... }, // 用来对资产进行一些基础的描述
 "properties": { ... },
 "geometricError": 100, // 用来决定该节点是否被渲染
 "root": { // 3dtile的根节点。
 "geometricError": 20,
 "boundingVolume": {
 "region": [ ... ] // 用来包裹子节点的包围盒。
 },
 "refine": "ADD",
 "children": [
 {
 "geometricError": 10,
 "boundingVolume": { ... },
 "content": {
 "uri": "house.b3dm"//用来实际渲染的内容,可以是.b3dm数据(即异构的模型),                       
 },
     "children": [
     {
     "geometricError": 5,
     "boundingVolume": { ... },
     "content": {
     "uri": "detailsA.b3dm"
     },
     }, {
     "geometricError": 5,
     "boundingVolume": { ... },
     "content": {
     "uri": "detailsB.b3dm"
     },
     }
     ]
 }, {
 "geometricError": 10,
 "boundingVolume": { ... },
 "content": {
     "uri": "tree.pnts"// .pnts数据(即点云数据),
     },
 }, {
     "geometricError": 10,
     "boundingVolume": { ... },
     "content": {
     "uri": "fence.i3dm" // 实例化数据
     },
 }, {
     "geometricError": 10,
     "boundingVolume": { ... },
     "content": {
     "uri": "external.json" // 其他的tile
     },
     }
 ]
 }
}

其中asset是用来对资产进行一些基础的描述。

properties : 是用来与3dtile相关联的一些属性信息。

geometricError : 用来决定该节点是否被渲染。这个参数可以用来判断当前应该渲染哪一个层级的数据。在运行时,程序会将这个几何误差,转化为屏幕空间错误(SSE)。SSE根据屏幕上的像素来量化可见的几何误差。当SSE超过某个阈值时,运行时将呈现更高级级的细节。SSE计算如下

sse = (geometricError ⋅ screenHeight) / (tileDistance ⋅ 2 ⋅ tan(fovy / 2))
​

其中geometricError 就是存储在tile中的数据,screenHeight就是真实渲染的屏幕的像素高度,tileDistance就是相机距离tile的距离,fov就是视锥的开放角。

root : 是3dtile的根节点。

boundingVolume : 用来包裹子节点的包围盒。3dtile的包围盒用三种类型。sphere,box,region。结构如下

boundingVolume : {
"sphere" : [
  1 , 1 ,1 , // 包围球的中心点
  100 // 半径
]
}
boundingVolume : {
    "box" : [
        0 , 0 , 10, // 中心点
        20 , 0 , 0, // x-半轴长度
        0 , 30 , 0, // y-半轴长度
        0 , 0 , 10 // z-半轴长度
    ]
}
​
boundingVolume : {
    "region" : [ 
        -1.319700, // 西
        0.6. // 南
        -1.33, // 东
        0.6, // 北
        0.0, // 最小高度
        20.0 // 最大高度
    ]
}

需注意的是,region采用的地理参考系,即四至范围计算参考wgs84椭球,可以简单理解为是经纬度,不过这个经纬度以弧度的形式表达。

content : 用来实际渲染的内容,可以是.b3dm数据(即异构的模型), 可以是.pnts数据(即点云数据), 可以是.i3dm数据(即大量需要实例化的模型数据),当然也可以是另一个tileset。

children : 即该tile的子节点是一个数组,一个tile下面可以挂若干个子节点,一个子节点下,还可以挂任意数据的子节点,如果你想的话,可以创造一个无限深的树。

末尾

上面只是简单的介绍了一下3dtile的具体组成结构,至于内部数据是如何组织的,如何将一个大规模模型数据生成3dtile文件,如何在浏览器渲染3dtile这又是另外一个话题。