导言
五一假期闲来无事,想起最近在看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这又是另外一个话题。