本文为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!
哈喽,大家好 我是
xy
👨🏻💻。这篇文章是Cesium 三维地球可视化从入门到进阶
专栏的第二篇,这篇文章主要对 Cesium 中基础核心类 Viewer、Scene 属性的一些使用讲解以及如何架加载第三方影像、地形服务。
在 Cesium
中有几个比较核心的类,也是开发过程中比较常用的:
Viewer
: Cesium 的核心类,对应着 Cesium 展示三维要素内容的主窗口Scene
: 是在 Viewer 或 CesiumWidget 内部隐式创建的Camera
:Camera
主要用来描述和操作场景的视角
视图 Viewer
Viewer
是 Cesium
的核心类,对应着 Cesium
展示三维要素内容的主窗口。
它不仅仅是包含三维地球的视窗,还包含一些基础控件,所以在定义 Viewer
对象的同时需要设定基础部件
、图层
等的初始化状态。
Cesium
开发的大部分工作在 Scene
场景中执行,包括调用图层
、3D Tiles
数据加载、场景交互
等。
另外 Cesium
提供了 Entity
、DataSource
等封装好的数据加载方式,降低了三维开发难度。
Viewer
对象主要包括如下属性:
camera
:相机属性,主要用于控制视角;widgets
(非属性):widgets
并非Viewer
对象的属性,在这里特指所有控件:animation
:动画控件;baseLayerPicker
:影像图层选择器;fullscreenButton
:全屏按钮;geocoder
:查找位置;homeButton
:返回视角到初始位置;navigationHelpButton
:帮助按钮;timeline
:时间轴;vrButton
:VR 按钮。
imageryLayers
:影像图层集合;terrainProvider
:地形提供者;entities
:实体集合;dataSources
:矢量数据集合;Event
(非属性):Event
并非Viewer
对象的属性,在这里特指所有事件:screenSpaceEventHandler
:屏幕操作事件;selectedEntityChanged
:选取实体事件;trackedEntityChanged
:追踪实体事件。
scene
:场景,scene
是Viewer
对象的属性,但它也是 Cesium 中的一个关键的对象,用于添加图形(primitive
)、添加场景特效和添加场景事件
在上一篇文章中,我们已经对 Viewer 的一些基本的配置做了详解, 如果还不会配置的小伙伴可以直接点击链接去学习: 三维地球可视化从入门到进阶 - 基础详解
场景 Scene
Scene
是构建场景
的类, 是 Cesium
中非常重要的类。Cesium
开发大多基于 Scene
类,其主要包含四部分内容:
- 基础地理环境设置,如
地球
参数(globe)、光照
(light)、雾
(fog)、大气
(skyAtmosphere) - 基础图层设置,包含
地图图层
、地形图层
等 - 场景数据,
Cesium
底层空间数据绘制方式是依赖Primitive
。Primitive API 功能强大而且非常灵活.为程序员绘制高级图形提供很大自由度、开发者可根据图形学原理自定义高级图形。技术难度较大,对于初学者较为困难,相比较面言Entity
封装程度高,构造简单,使用便捷,目前不支持自定义。3D Tiles
是 Primitive 的非常重要部分,可以实现大数据量加载 - 场景交互函数,如
pick
(鼠标事件)、camera
(相机事件)
相机 Camera
Cesium
通过相机来控制场景中的视域
、旋转
、缩放
、平移
等操作都可控制相机移动,使用相机Camera
操作场景分为如下几类:
- 飞行 fly:
flyHome
、flyTo
和flyToBoundingSphere
,与 fly 有关的方法的特点就是在改变相机视角时会伴随飞行动画;这类方法一定会改变相机的位置,但是不一定会改变相机的朝向; - 缩放 zoom:
zoomIn
和zoomOut
,与 zoom 有关的方法类似于使用鼠标滚轮来操作场景进行缩小或放大;这类方法不会改变相机的朝向,只会改变相机的位置; - 移动 move :
moveBackward
、moveDown
、moveForward
、moveLeft
、moveRight
和moveUp
,与 move 有关的方法就是在前后左右上下这六个方向上移动相机,这类方法不会改变相机的朝向,只会改变相机的位置; - 视角 look :
lookDown
、lookLeft
、lookRight
和lookUp
,与 look 有关的方法就是在相机位置不变的情况下,调整相机镜头的上下左右四个方向朝向,这类方法不会改变相机的位置,只会改变相机的朝向; - 扭转 twist :
twistLeft
和twistRight
,与 twist 有关的方法就是在相机位置不变的情况下,调整相机视角向左(逆时针)或向右(顺时针)扭转,这类方法不会改变相机的位置,只会改变相机的朝向; - 旋转 rotate :
rotateDown
、rotateLeft
、rotateRight
和rotateUp
,与 rotate 有关的方法会根据提供的角度参数旋转相机视角,这类方法会改变相机的位置,也会改变相机的朝向; - 其他操作相机的方法:
setView
直接将相机视角定位到某个位置;lookAt
直接将相机视角定位到某个位置,但是会锁定相机视角。
viewer Scene Camera 常用配置
下面给大家总结一些 viewer
Scene
Camera
常用的一些配置
- 去除 Cesium 版权图标
viewer.cesiumWidget.creditContainer.style.display = "none";
- 显示帧数
viewer.scene.debugShowFramesPerSecond = true;
- 增加太阳光照
viewer.scene.globe.enableLighting = true;
- 大气层显示
viewer.scene.skyAtmosphere.show = true;
- 开启地形深度检测
viewer.scene.globe.depthTestAgainstTerrain = true;
- 禁止相机进入地下
viewer.scene.globe.depthTestAgainstTerrain = true;
- 右键拖拽场景倾斜
viewer.scene.screenSpaceCameraController.tiltEventTypes = Cesium.CameraEventType.RIGHT_DRAG
- 关闭抗锯齿
viewer.scene.fxaa = false;
viewer.scene.postProcessStages.fxaa.enabled = false;
- 鼠标操作惯性控制
//关闭旋转惯性
viewer.scene.screenSpaceCameraController.inertiaSpin = 0
//关闭平移惯性
viewer.scene.screenSpaceCameraController.inertiaTranslate = 0
//关闭缩放惯性
viewer.scene.screenSpaceCameraController.inertiaZoom = 0
- 自动调整分辨率
var supportsImageRenderingPixelated =
viewer.cesiumWidget._supportsImageRenderingPixelated;
if (supportsImageRenderingPixelated) {
var vtxf_dpr = window.devicePixelRatio;
while (vtxf_dpr >= 2.0) {
vtxf_dpr /= 2.0;
}
viewer.resolutionScale = vtxf_dpr;
}
- 默认定位到中国
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
75.0, // 东
0.0, // 南
140.0, // 西
60.0 // 北
);
- 修改天空背景盒样式
var scene=viewer.scene;
scene.skyBox = new Cesium.SkyBox({
sources : {
positiveX: "/skyBox/00h+00.jpg",
negativeX: "skyBox/12h+00.jpg",
positiveY: "/skyBox/06h+00.jpg",
negativeY: "/skyBox/18h+00.jpg",
positiveZ: "/skyBox/06h+90.jpg",
negativeZ: "/skyBox/06h-90.jpg",
}
});
加载第三方影像
Cesium 加载的虚拟地球默认是有影像的,如图:
默认使用的影像为“Bing Maps Aerial”:
除了图中列出的一些影像,开发者可以通过 Cesium 中的ImageryProvider
影像提供者类创建所需的影像,截止 2022 年 4 月 12 日,在 Cesium 1.92 版本中共有 14 种ImageryProvider
影像提供者类(不包括抽象类ImageryProvider
):
ArcGisMapServerImageryProvider
:由 ArcGIS Map Server 提供的影像服务;BingMapsImageryProvider
:由 Bing Map 提供的影像服务;GoogleEarthEnterpriseImageryProvider
:由 Google Earth Enterprise 提供的影像服务;GridImageryProvider
:网格影像服务;IonImageryProvider
:由 Cesium Ion 提供的影像服务,Cesium Ion 为 Cesium 官方提供的云服务。MapboxImageryProvider
:由 Mapbox 提供的影像服务;MapboxStyleImageryProvider
:由 Mapbox 提供的可以修改样式 style 的影像服务;SingleTileImageryProvider
:由单个图像提供的影像服务;TileCoordinatesImageryProvider
:切片 tile 坐标影像服务,可以在每一个切片周围绘制一个框并标识其 X,Y 坐标和 Level 层级,主要用于调试;TileMapServiceImageryProvider
:由 MapTiler 提供的影像服务;UrlTemplateImageryProvider
:通过指定的 URL 加载影像服务;WebMapServiceImageryProvider
:由 Web Map Service(WMS)提供的影像服务;WebMapTileServiceImageryProvider
:由 Web Map Tile Service(WMTS)提供的影像服务。
加载影像图层的方法共有两种:
- 在初始化 viewer 的时候添加;
在初始化Viewer
时可在第二个参数Viewer.ConstructorOptions
中添加imageryProvider
属性并提供一个ImageryProvider
对象:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
})
})
- 通过 viewer.imageryLayers.addImageryProvider 方法添加。
使用viewer.imageryLayers.addImageryProvider
方法,顾名思义需要传入一个ImageryProvider
对象:
const ArcGisImagery = viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
}))
ArcGisMapServerImageryProvider
加载 Arcgis 影像服务的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
})
})
加载后的效果如下:
BingMapsImageryProvider
加载 Bing 影像服务的代码如下,其中key
属性需要在Bing maps Dev Center中申请,按照页面提示申请即可:
viewer.imageryProvider = new Cesium.BingMapsImageryProvider({
url: 'https://dev.virtualearth.net',
key: 'xxx',
mapStyle : Cesium.BingMapsStyle.AERIAL
})
加载后的效果如下:
GridImageryProvider
加载 Grid 网格影像服务的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.GridImageryProvider()
})
加载后的效果如下:
SingleTileImageryProvider
加载本地图片如下:
加载的代码如下:
viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({
url: './data/worldimage.jpg'
}))
加载后的效果如下:
TileCoordinatesImageryProvider
加载 TileCoordinates 影像服务的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.TileCoordinatesImageryProvider()
})
UrlTemplateImageryProvider
Google 影像服务
众所周知的原因,谷歌地图影像在中国大陆无法使用
加载谷歌地图影像的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali"
})
})
加载后的效果如下:
高德影像服务
加载高德地图影像的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}"
})
})
加载后的效果如下:
WebMapTileServiceImageryProvider
天地图影像(推荐)
在使用天地图之前请注册一个天地图账号
以及一个天地图 Token
,创建完成后可以在 Cesium
中加载天地图服务:
const tdtToken = '' // 填入你创建的天地图Token
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
url: `http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=${tdtToken}`,
layer: "tdtBasicLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",
})
})
加载后的效果如下:
加载地形服务
Cesium 默认是不包含地形的,准确的说应该是 Cesium 默认加载的地形是没有起伏效果的,,如下图所示,在包含山脉的地区是看不到地形起伏的:
默认使用的地形为”WGS84 Ellipsoid“:
地形提供者 TerrainProvider
与影像类似,在 Cesium 中提供了一些地形提供者TerrainProvider
用于加载各类地形,截止 2022 年 4 月 12 日,在 Cesium 1.92 版本中共有 6 种TerrainProvider
地形提供者(不包括接口TerrainProvider
):
ArcGISTiledElevationTerrainProvider
:由 ArcGIS 提供的地形服务;CesiumTerrainProvider
:由 Cesium 官方提供的地形服务;CustomHeightmapTerrainProvider
:自定义高程的地形服务;EllipsoidTerrainProvider
:高程为 0 的地形服务,如果初始化时不指定地形,那么默认的就是使用的该地形服务;GoogleEarthEnterpriseTerrainProvider
:由 GoogleEarth 提供的地形服务;VRTheWorldTerrainProvider
:由 VRTheWorld 提供的地形服务。
与加载影像图层十分类似,加载地形的方法也有两种:
- 在初始化
viewer
的时候添加;
注意,一个视图下地形只能加载一个,而影像图层是可以加载多个的,同一视图下可以叠加多个影像。另外,从语义上来说,每一个影像图层都是一个imageryLayer
,所有的imageryLayer
通过ImageryLayerCollection
来管理,添加一个影像图层用的方法是addImageryProvider
,注意动词“add
”,而对于地形来说,是直接给viewer.terrainProvider
赋值的。
在初始化Viewer
时可在第二个参数Viewer.ConstructorOptions
中添加terrainProvider
属性并提供一个TerrainProvider
对象:
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: new Cesium.ArcGISTiledElevationTerrainProvider({
url: 'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
})
})
- 通过
viewer.terrainProvider
赋值添加。
通过viewer.terrainProvider
赋值添加的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer")
const ArcGisTerrainProvider = new Cesium.ArcGISTiledElevationTerrainProvider({
url: 'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
})
viewer.terrainProvider = ArcGisTerrainProvider
ArcGISTiledElevationTerrainProvider
加载 Arcgis 地形服务的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer")
const terrainProvider = new Cesium.ArcGISTiledElevationTerrainProvider({
url: 'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
})
viewer.terrainProvider = terrainProvider
加载后的效果如下:
CesiumTerrainProvider
CesiumTerrainProvider
用于加载自行发布的地形服务或其他地形服务商发布的地形服务。
自行发布的地形服务
加载自行发布的地形服务代码如下,其中https://localhost/terrain
为地形服务的URL
:
const viewer = new Cesium.Viewer("cesiumContainer")
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: "https://localhost/terrain"
})
火星科技地形
参考Mars3D 地形,版权归火星科技所有,在此仅作为学习交流所用,侵删。
加载火星科技地形的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer")
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: 'http://data.marsgis.cn/terrain',
})
加载后的效果如下:
maptiler 地形
加载 maptiler 地形的伪代码如下,需要访问maptiler 官网注册账号获取key
:
const viewer = new Cesium.Viewer("cesiumContainer")
const maptilerKey = 'xxx'
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: `https://api.maptiler.com/tiles/terrain-quantized-mesh/?key=${maptilerKey}`,
requestVertexNormals: true
})
加载后的效果如下:
CustomHeightmapTerrainProvider
加载自定义高程地形的代码如下,通过回调函数callback
获取高程,这个TerrainProvider
用的很少:
const viewer = new Cesium.Viewer("cesiumContainer")
let width = 64
let height = 64
viewer.terrainProvider = new Cesium.CustomHeightmapTerrainProvider({
callback: (x, y, level) => {
let buffer = new Float32Array(width * height)
for (let yy = 0; yy < height; yy++) {
for (let xx = 0; xx < width; xx++) {
let v = (y + yy / (height - 1)) / Math.pow(2, level)
let heightValue = 8000 * (Math.sin(4000 * v) * 0.5 + 0.5)
let index = yy * width + xx
buffer[index] = heightValue
}
}
return buffer
},
width: width,
height: height,
})
EllipsoidTerrainProvider
EllipsoidTerrainProvider
是高程为 0 的地形,若初始化时不指定地形,那么默认的就是使用的该地形服务,加载EllipsoidTerrainProvider
的代码如下:
const viewer = new Cesium.Viewer("cesiumContainer")
viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider()
🎯 这篇文章是 Cesium 三维地球可视化从入门到进阶
专栏的第二篇文章,主要是对 Cesium 中基础核心类 Viewer、Scene 属性的一些使用讲解以及如何架加载第三方影像、地形服务。
🎯 在后续的文章中, 将会分享更多
的实践案例
,如果你也对 三维可视化
比较感兴趣的话,欢迎关注我一起学习
🎯 Github 仓库地址:https://github.com/xushanpei/Cesium_Study_Cases
写在最后
公众号
:前端开发爱好者
专注分享web
前端相关技术文章
、视频教程
资源、热点资讯等,如果喜欢我的分享,给 🐟🐟 点一个赞
👍 或者 ➕关注
都是对我最大的支持。
大家好,我 xy,是一名前端 🤫 爱好:瞎折腾
如果你也是一名瞎折腾的前端欢迎加我微信交流哦...