Cesium 3D Tile是Cesium的一种特有的3D模型格式,其文件名后缀为.b3dm,而要在自己开发的平台上调用这些3D Tile,一般为通过后缀为.json格式的文件来调用.b3dm格式的3D Tile。
3D Tiles是一种开放的三维空间数据标准,其设计目的主要是为了提升大的三维场景中模型的加载和渲染速度。假如要在Web客户端渲染一个非常大的三维模型(如一个大城市的建筑模型),如果把模型全部下载到客户端并且进行渲染,这个过程所消耗的时间对于使用普通电脑的用户来说是不能接受的。然而,在绝大多数的用户交互式的三维场景中,都只需要渲染模型的一小部分,将三维模型全部加载并渲染是一种极大的资源浪费,3D Tiles为这个问题提供了一个很好的解决方案。将三维空间数据组织为3D Tiles格式,可以实现模型的按需加载和渲染,从而实现流畅的三维模型浏览体验。
3DTiles数据特点
开放且灵活。作为一种开放式数据规范,3D Tiles的切片方案灵活可变,三维模型的切片大小和覆盖范围可以人为设置。此外,3D Tiles还能够适配三维空间中多种空间分区方案,包括KD树、四叉树、八叉树、普通网格,以及其他空间数据结构等。
异质性支持。通过一组已定义的文件格式,可以将多种类型的三维地理空间要素(包括倾斜摄影数据、BIM/CAD数据、三维建筑模型、实例化要素和点云数据)转换为三维形式的单个数据集同时又允许多种不同格式标准的模型显示在同一个场景中。
专为三维可视化设计。3D Tiles建立在gITF格式之上,并引入了三维图形领域的技术,3D Tiles 格式的基础就是树状模型对象的层次结构(hierarchical levels of deail.HLOD)。传统的细节层次模型会访问场景中所有对象或者节点,针对每一个节点判断是否符合值染的条件:而 HLOD具备层次结构,当不满足细化放染条件的时候,场最只会直染父级对象或节点,不会访同子节点,因此计算量相对较小。
将大量三维模型预先处理成3D Tiles的格式,可以让浏览器端从请求数据到webGL直染数据的流程更快速和简单,减轻测览器端的处理压力。同时,因为三维模型预先处理成了分块的三维瓦片格式,所以也减少了WebGL 给制请求的数量。
可交互。3D Tles支持交互旋转和样式的设置,在WebGL中优化后,三维瓦片支持对单个模型的交互,如高亮显示鼠标悬停位置的模型,或删除一个三维建筑模型。还支持对单个模型的材质修改,如根据建筑高度和年代,可以设置不同的显示效果面不需要重新更新代码。3D Tiles用于流式传输三维空间信息,包括建筑物、树木、点云和矢量数据等。
3DTiles数据结构
3D Tiles的格式由两部分组成,一个是JSON格式的数据组织文件(tileset.json),另外是每个瓦片节点对应的模型文件,3D Tiles支持的模型文件格式有. b3dm、.i3dm、.pnts、.vctr、.cmpt五种。
3D Tiles模型文件类型
tileset.json结构如下:
{
"asset": {
"version": "1.0"
},
"extras": {
"scenetree": "scenetree.json"
},
"geometricError": 3177.09515705891,
"properties": null,
"refine": "REPLACE",
"root": {
"boundingVolume": {
"box": [
4.65661287307739e-10,
0.166235401295125,
35.2569177309051,
1588.54757852945,
0,
0,
0,
1181.13848758582,
0,
0,
0,
34.564118469134
]
},
"children": [
{
"boundingVolume": {
"box": [
0.124150419024886,
0.0280173681455835,
34.2241047454536,
1588.36216882034,
0,
0,
0,
1181.1412862779,
0,
0,
0,
33.270950091015
]
},
"content": {
"uri": "NoLod_0.b3dm"
},
"geometricError": 0.0,
"refine": "REPLACE"
}
],
"geometricError": 3177.09515705891,
"transform": [
-0.895820508655044,
-0.44441603962168,
0.0,
0.0,
0.285099483582047,
-0.57468214832474,
0.767110626219003,
0.0,
-0.340916266455956,
0.687193431374197,
0.641514837818961,
0.0,
-2177436.70605816,
4389113.54154921,
4069934.44996518,
1.0
]
}
}
- asset是一个包含了整体tileset元数据属性的对象,其中version属性是定义3D Tiles 版本的字符串,版本号定义了tileset. json的JSON格式和瓦片格式的基础。tilesetVersion 属性是一个选填的字符串,用于定义特定应用中tileset的版本,可以用于更新tileset。
- properties规定了瓦片集最大外包矩形地理空间范围,由经度、纬度、高度三个属性的最大值和最小值界定。
- geometrieError定义了一个非负误差(以米为单位),在这个误差下瓦片集不被渲染。
- root用于定义根瓦片,root.geometricError与最高层级tileset.json的geometricError不同。后者是整个瓦片集不被渲染的误差,前者是只有根瓦片被渲染的误差。
- children定义子瓦片对象的数组。每个子瓦片都有boundingVolume,这个边界体被父瓦片的boundingVolume完全包围,通常子瓦片的geometricError要小于父瓦片的geometricError。对于叶子瓦片而言,子瓦片数组的长度为零。
加载3Dtile核心代码
注意:将tileset添加到scene.primitive而不是scene.entity ,3D Tiles不是Entity API的一部分。
//加载倾斜摄影图像
function init3Dtiles() {
const tileSet = new Cesium3DTileset({
url: "http://127.0.0.1/data/tileset.json",
maximumMemoryUsage: 100,//不可设置太高,目标机子空闲内存值以内,防止浏览器过于卡
maximumScreenSpaceError: 32,//用于驱动细节细化级别的最大屏幕空间错误;较高的值可提供更好的性能,但视觉质量较低。
maximumNumberOfLoadedTiles: 1000, //最大加载瓦片个数
shadows: false,//是否显示阴影
skipLevelOfDetail: true,// 确定是否应在遍历期间应用详细级别跳过(默认false)
baseScreenSpaceError: 1024,//When skipLevelOfDetailis true,在跳过详细级别之前必须达到的屏幕空间错误(默认1024)
skipScreenSpaceErrorFactor: 16,// 定义要跳过的最小屏幕空间错误的乘数。与 一起使用skipLevels来确定要加载哪些图块(默认16)
skipLevels: 1,//skipLevelOfDetail是true 一个常量,定义了加载图块时要跳过的最小级别数。为 0 时,不跳过任何级别。与 一起使用skipScreenSpaceErrorFactor来确定要加载哪些图块。(默认1)
immediatelyLoadDesiredLevelOfDetail: false,//当skipLevelOfDetail是时true,只会下载满足最大屏幕空间错误的图块。忽略跳过因素,只加载所需的图块(默认false)
loadSiblings: false,// 如果为true则不会在已加载完概况房屋后,自动从中心开始超清化房屋 --- 何时确定在遍历期间skipLevelOfDetail是否true始终下载可见瓦片的兄弟姐妹(默认false)
cullWithChildrenBounds: true,//是否使用子边界体积的并集来剔除瓦片(默认true)
dynamicScreenSpaceError: true,//减少距离相机较远的图块的屏幕空间错误(默认false)
dynamicScreenSpaceErrorDensity: 0.00278,//数值加大,能让周边加载变快 --- 用于调整动态屏幕空间误差的密度,类似于雾密度(默认0.00278)
dynamicScreenSpaceErrorFactor: 4.0,// 用于增加计算的动态屏幕空间误差的因素(默认4.0)
dynamicScreenSpaceErrorHeightFalloff: 0.25//密度开始下降的瓦片集高度的比率(默认0.25)
});
viewer.scene.primitives.add(tileSet);
viewer.zoomTo(tileSet);
}
示例
参考官方示例:Cesium Sandcastlehttps://sandcastle.cesium.com/?src=3D%20Tiles%20Adjust%20Height.html
tileset.json在线地址:https://sandcastle.cesium.com/SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json
{
"asset": {
"version": "1.0",
"tilesetVersion": "1.2.3"
},
"extras": {
"name": "Sample Tileset"
},
"properties": {
"id": {
"minimum": 0,
"maximum": 9
},
"Longitude": {
"minimum": -1.3197192952275933,
"maximum": -1.319644104024109
},
"Latitude": {
"minimum": 0.698848878034009,
"maximum": 0.6989046192460953
},
"Height": {
"minimum": 6.161747192963958,
"maximum": 85.41026367992163
}
},
"geometricError": 240,
"root": {
"boundingVolume": {
"region": [
-1.3197209591796106,
0.6988424218,
-1.3196390408203893,
0.6989055782,
0,
88
]
},
"geometricError": 70,
"refine": "ADD",
"content": {
"uri": "parent.b3dm",
"boundingVolume": {
"region": [
-1.3197004795898053,
0.6988582109,
-1.3196595204101946,
0.6988897891,
0,
88
]
}
},
"children": [
{
"boundingVolume": {
"region": [
-1.3197209591796106,
0.6988424218,
-1.31968,
0.698874,
0,
20
]
},
"geometricError": 0,
"content": {
"uri": "ll.b3dm"
}
},
{
"boundingVolume": {
"region": [
-1.31968,
0.6988424218,
-1.3196390408203893,
0.698874,
0,
20
]
},
"geometricError": 0,
"content": {
"uri": "lr.b3dm"
},
"extras": {
"id": "Special Tile"
}
},
{
"boundingVolume": {
"region": [
-1.31968,
0.698874,
-1.3196390408203893,
0.6989055782,
0,
20
]
},
"geometricError": 0,
"content": {
"uri": "ur.b3dm"
}
},
{
"boundingVolume": {
"region": [
-1.3197209591796106,
0.698874,
-1.31968,
0.6989055782,
0,
20
]
},
"geometricError": 0,
"content": {
"uri": "ul.b3dm"
}
}
]
}
}
其中引入了好几个b3dm文件,先全部下载到本地。其下载地址如下:
<template>
<div id="cesiumContainer"></div>
</template>
<script setup>
import * as Cesium from 'cesium';
import { onMounted } from 'vue';
onMounted(() => {
const viewer = new Cesium.Viewer("cesiumContainer", {
shadows: true,//显示模型阴影
});
const tileset = new Cesium.Cesium3DTileset({
url: "tileset.json",
});
viewer.scene.primitives.add(tileset);
viewer.flyTo(tileset)
})
</script>
<style scoped>
#cesiumContainer {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>