- Cesium加载3D Tiles数据:
- 作业
9 - 3D Tiles
我们团队有时把Cesium描述成一个真实世界数据的3D游戏引擎。然而,使用真实世界的数据比使用典型的视频游戏数据资料要困难得多,因为真实数据可能是难以置信的高分辨率,并且需要精确的可视化。幸运的是,Cesium 与开源社区合作开发了3D Tiles,这是一个开放的规范,用于传输海量的异构三维地理空间数据集。
使用概念上类似于Cesium的terrain和imagery的流技术,3D Tiles 使得可以查看原本不能交互式查看的巨大的模型,包括建筑物数据集、CAD(或BIM)模型、点云和摄影测量模型。
- The 3D Tiles Inspector 是一种在遮罩hood下提供查看能力的调试工具。
下面是一些展示不同格式的3D Tiles演示:
在我们的应用中,我们将使用Cesium3DTileset通过展示纽约所有建筑物的全3D模型来为我们的可视化添加现实主义!这种纽约 tileset托管在Cesium Ion中,我们可以使用Cesium3DTileset.fromIonAssetId添加它:
// Load the NYC buildings tileset // 旧版本 // var city = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(3839) })); // 新版本 const city = await Cesium.Cesium3DTileset.fromIonAssetId(75343, {});
你可能注意到建筑物没有正确地定位在地平面上。幸运的是,它很容易修复。我们可以通过修改模型矩阵modelMatrix来调整tileset的位置。
我们可以通过将tileset的边界球转换成地图Cartographic,然后添加期望的偏移量并重置模型矩阵,从地面找到模型modelMatrix的当前偏移量。
// Adjust the tileset height so its not floating above terrain var heightOffset = -32; var boundingSphere = city.boundingSphere; var cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0); var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset); var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3()); city.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
现在在我们的场景中有110万个建筑模型流。
3D Tiles 还允许我们使用3D Tiles styling语言 来调整我们的样式。3D Tiles 样式定义了用于评估颜色(RGB和透明度)的表达式,并显示了Cesium3DTileFeature特征的属性,这是tileset的一部分,例如城市中的单个建筑物。样式通常基于存储在瓦片的批处理表中的特征属性。特征属性可以是高度、名称、坐标、构造日期等任何东西,但被构建到tileset asset 中。样式是用JSON定义的,而表达式是在JavaScript的小子集中编写的,用于样式化。此外,样式语言提供了一组内置函数来支持常见的数学运算。
一个Cesium3DTilesetStyle的例子如下:
var defaultStyle = new Cesium.Cesium3DTileStyle({ color : "color('white')", show : true });
上述代码使我们NYC的tileset是白色并且总是可见的。为了实际设置tileset的样式,我们设置city.style:
city.style = defaultStyle;
我们还可以定义许多我们喜欢的样式。比如,让建筑变透明:
var transparentStyle = new Cesium.Cesium3DTileStyle({ color : "color('white', 0.3)", show : true }); city.style = transparentStyle;
在我们的tileset中使用相同的样式来达到每一个特征只是皮毛工作。我们还可以使用特定于每个特征的属性来确定造型。下面是一个基于建筑物高度的建筑物颜色的例子:
var heightStyle = new Cesium.Cesium3DTileStyle({ color : { conditions : [ ["${Height} >= 300", "rgba(45, 0, 75, 0.5)"], ["${Height} >= 200", "rgb(102, 71, 151)"], ["${Height} >= 100", "rgb(170, 162, 204)"], ["${Height} >= 50", "rgb(224, 226, 238)"], ["${Height} >= 25", "rgb(252, 230, 200)"], ["${Height} >= 10", "rgb(248, 176, 87)"], ["${Height} >= 5", "rgb(198, 106, 11)"], ["true", "rgb(127, 59, 8)"] ] } });
为了在样式间交换,我们可以添加更多的代码来侦听HTML输入:
const viewer = new Cesium.Viewer("cesiumContainer", { terrain: Cesium.Terrain.fromWorldTerrain(), // infoBox: false, }); try { const city = await Cesium.Cesium3DTileset.fromIonAssetId(75343, {}); console.log(city); viewer.scene.primitives.add(city); var heightOffset = -32; var boundingSphere = city.boundingSphere; var cartographic = Cesium.Cartographic.fromCartesian( boundingSphere.center ); var surface = Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, 0.0 ); var offset = Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, heightOffset ); var translation = Cesium.Cartesian3.subtract( offset, surface, new Cesium.Cartesian3() ); city.modelMatrix = Cesium.Matrix4.fromTranslation(translation); var transparentStyle = new Cesium.Cesium3DTileStyle({ color: "color('white', 0.3)", show: true, }); city.style = transparentStyle; var heightStyle = new Cesium.Cesium3DTileStyle({ color: { conditions: [ ["${Height} >= 300", "rgba(45, 0, 75, 0.5)"], ["${Height} >= 200", "rgb(102, 71, 151)"], ["${Height} >= 100", "rgb(170, 162, 204)"], ["${Height} >= 50", "rgb(224, 226, 238)"], ["${Height} >= 25", "rgb(252, 230, 200)"], ["${Height} >= 10", "rgb(248, 176, 87)"], ["${Height} >= 5", "rgb(198, 106, 11)"], ["true", "rgb(127, 59, 8)"], ], }, show: "${Height} > 0", meta: { description: '"Building id ${id} has height ${Height}."', }, }); city.style = heightStyle; viewer.zoomTo( city, new Cesium.HeadingPitchRange( 0.0, -0.5, city.boundingSphere.radius / 4.0 ) ); const options = [ { text: "高度", onselect: function () { city.style = heightStyle; }, }, { text: "透明度", onselect: function () { city.style = transparentStyle; }, }, ]; // viewer.scene.imageryLayers和viewer.imageryLayers是同一对象 Sandcastle.addToolbarMenu(options); } catch (error) { console.log(`Error loading tileset: ${error}`); }
更多关于3D Tiles的例子、如何使用及调整样式,请查看[the 3D Tiles demos](http://111.22.69.99:58080/cesium/Apps/Sandcastle/?src=Hello%20World.html&label=3D Tiles)。
3D Tiles例子:
Cesium加载3D Tiles数据:
(1)3D Tiles数据介绍:
带有LOD(层次细节模型)的glTF,专门为流式传输和渲染海量3D地理空间数据设计,例如倾斜摄影、3D建模、BIM/CAD、实例化要素集的点云。
3D Tiles相关类介绍:
cesium更新版本后将Cesium3DTileFeature类的getPropertyNames()换成getPropertyIds()。
(2)添加3D Tiles数据代码:
// 添加3D Tiles的数据源,需要使用异步函数加载
async function add3DTile() {
const tileset = await Cesium.Cesium3DTileset.fromUrl(
"/Tileset/tileset.json" // 瓦片索引
)
// 1,添加tileset
viewer.scene.primitives.add(tileset)
// 视图定位
viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(
0.0, -0.5, tileset.boundingSphere.radius * 2.0
))
const boundingSphere = tileset.boundingSphere
console.log(boundingSphere.center)
// 2,设置样式
const properties = tileset.properties
if (Cesium.defined(properties) && Cesium.defined(properties.Height)) {
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
["${Height} >= 83", "color('purple', 0.5)"],
["${Height} >= 80", "color('red')"],
["${Height} >= 70", "color('orange')"],
["${Height} >= 12", "color('yellow')"],
["${Height} >= 7", "color('lime')"],
["${Height} >= 1", "color('cyan')"],
["true", "color('blue')"]
]
}
})
}
// 3,添加鼠标拾取要素
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
// 绑定鼠标左点击事件
handler.setInputAction((e) => {
console.log(e)
let windowPosition = e.position // 屏幕坐标
// 屏幕坐标转世界坐标
const ray = viewer.camera.getPickRay(windowPosition)
const catesian = viewer.scene.globe.pick(ray, viewer.scene)
// 世界坐标转经纬度坐标
const lat = Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(catesian).latitude)
const lng = Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(catesian).longitude)
console.log('经度坐标是:' + lng + ';纬度坐标是:' + lat)
// 获取要素
const feature = viewer.scene.pick(windowPosition)
if (Cesium.defined(feature) && feature instanceof Cesium.Cesium3DTileFeature) {
const propertyIds = feature.getPropertyIds()
console.log(propertyIds)
const length = propertyIds.length
for (let i = 0; i < length; ++i) {
let propertyId = propertyIds[i]
console.log(propertyId + ': ' + feature.getProperty(propertyId))
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
add3DTile()
(3)3D Tiles制作平移动画:
// 4,3DTiles制作向上平移的动画
const adjustTilesetHeight = (tileset, height = 10) => {
// 计算出模型模型包围球的中心点,转弧度制
const cartography = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center)
// 计算与模型包围球中心点经纬度相同的地表点位
const surface = Cesium.Cartesian3.fromRadians(
cartography.longitude, cartography.latitude,
0
)
// 计算调整高度后的模型包围球的中心点
const offset = Cesium.Cartesian3.fromRadians(
cartography.longitude, cartography.latitude,
height
)
// 计算差向量
const diff = Cesium.Cartesian3.subtract(
offset, surface, new Cesium.Cartesian3()
)
console.log(diff);
// 修改模型的变换矩阵
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(diff)
}
let h = 10
setInterval(() => {
adjustTilesetHeight(tileset, h++)
}, 1000)
作业
- 使用下拉列表修改模型的透明度和颜色。
- 3D Tiles制作平移动画。
- 加载华旦的3dtiles的url(http://111.22.69.99:58080/cesium/Apps/SampleData/Cesium3DTiles/huadan/tileset.json)到地图中,并调整离地高度,使用flyTo调整相机位置。
- (选做)参考天地图官方文档三维服务 - 天地图 帮助文档 (tianditu.gov.cn),使用天地图卫星影像底图和地形图+华旦的3Dtiles模型。