本教程将介绍影像图层的基本概念及相关的 CesiumJS API。
CesiumJS 支持从多个服务获取、绘制和叠加高分辨率影像图层,包括 Cesium ion。借助 Cesium ion,您可以通过网络实时加载和展示精选的高分辨率影像,或者将自己的栅格数据作为影像图层嵌入到 CesiumJS 应用程序中。这些影像图层可以排序和混合在一起,并且每个图层的亮度、对比度、伽马值、色调和饱和度都可以动态调整。
如果您有自己的影像数据,可以参考「无人机或卫星影像切片教程」。
快速开始
在 Sandcastle 中打开 Hello World 示例。该示例创建了一个 Viewer 小部件,并使用 Cesium ion 提供的 Bing Maps 航拍影像作为底图进行渲染。通过向 Viewer 构造函数提供额外的参数,可以指定不同的底图。下面我们使用带标签的 Bing Maps 影像:
// 您的访问令牌可以在 https://ion.cesium.com/tokens 上找到。
// 将 'your_access_token' 替换为您的 Cesium ion 访问令牌。
Cesium.Ion.defaultAccessToken = "your_access_token";
const viewer = new Cesium.Viewer("cesiumContainer", {
baseLayer: Cesium.ImageryLayer.fromWorldImagery({
style: Cesium.IonWorldImageryStyle.AERIAL_WITH_LABELS,
}),
baseLayerPicker: false,
});
创建 Cesium ion 账户
本教程将使用来自 Cesium ion 的影像数据。请创建一个账户以获取您的访问令牌,这样您就可以在本教程中使用这些影像数据。点击这里注册,并在上面的代码中使用您的令牌。如果您已经有账户,请点击这里登录。
在修改示例后,按 F8 运行它。
随着您放大或缩小,图层将根据需要动态加载和显示相应分辨率的影像数据。
添加另一个 Cesium ion 影像图层: 地球之夜。
首先需要在 Asset Depot 中搜索并添加 "Earth at Night" 图层。
添加完成后,前往 My Assets 查看并记下对应的资产 ID。如下图所示,资产 ID 为 3812。
在上述示例代码的基础上,添加以下代码以加载并显示 "Earth at Night" 图层:
const blackMarble = Cesium.ImageryLayer.fromProviderAsync(
Cesium.IonImageryProvider.fromAssetId(3812)
);
layers.add(blackMarble);
由于“地球之夜”图层是最后添加的,并且覆盖了全球范围,因此它遮挡了 Bing 图层。我们可以使用 layers.lower(blackMarble); 将地球之夜图层移到底部,还可以通过设置其透明度,将它与 Bing 图层混合,以更好地展示两个图层之间的关系:
blackMarble.alpha = 0.5; // 0.0 是透明的,1.0 是不透明的。
接下来,为了让夜间灯光更清晰,我们可以使用 brightness 属性来提高图层的亮度。
blackMarble.brightness = 2.0; // > 1.0 增加亮度,< 1.0 减少亮度。
最后,我们将添加第三个图层:在特定范围内绘制一张图片。
const cesiumLogo = Cesium.ImageryLayer.fromProviderAsync(
Cesium.SingleTileImageryProvider.fromUrl(
"../images/Cesium_Logo_overlay.png",
{
rectangle: Cesium.Rectangle.fromDegrees(
-75.0,
28.0,
-67.0,
29.75
),
}
)
);
layers.add(cesiumLogo);
效果如下图所示:
以下是完整的示例代码:
Cesium.Ion.defaultAccessToken = "your_access_token";
const viewer = new Cesium.Viewer("cesiumContainer", {
baseLayer: Cesium.ImageryLayer.fromWorldImagery({
style: Cesium.IonWorldImageryStyle.AERIAL_WITH_LABELS,
}),
baseLayerPicker: false,
});
const layers = viewer.scene.imageryLayers;
const blackMarble = Cesium.ImageryLayer.fromProviderAsync(
Cesium.IonImageryProvider.fromAssetId(3812)
);
blackMarble.alpha = 0.5;
blackMarble.brightness = 2.0;
layers.add(blackMarble);
const cesiumLogo = Cesium.ImageryLayer.fromProviderAsync(
Cesium.SingleTileImageryProvider.fromUrl(
"../images/Cesium_Logo_overlay.png",
{
rectangle: Cesium.Rectangle.fromDegrees(
-75.0,
28.0,
-67.0,
29.75
),
}
)
);
layers.add(cesiumLogo);
随时可用的影像
Sandcastle 中的 ion Assets 标签包含很多由 Cesium ion 托管的影像瓦片集,CesiumJS 集成了 Cesium ion,使得开发者可以非常方便地将这些托管在 Cesium ion 上的瓦片集添加到他们的应用中。许多瓦片集也可以在部署在本地环境使用。
更多影像提供程序
像示例中的前两个图层那样的高分辨率影像数据通常太大,无法完全载入内存或单个磁盘,因此这些影像就会被分割成较小的图块,称为瓦片。这些瓦片可以根据视图的需要逐步传输到客户端(即流式传输)。Cesium 支持多种不同的协议和标准,允许用户从不同的影像提供者那里请求地图瓦片(tiles)。大多数影像提供者提供基于 HTTP 的 REST 接口 请求瓦片,但不同的影像提供者在请求的格式和瓦片的组织方式上有所不同。Cesium 支持以下几种影像提供者:
- WebMapServiceImageryProvider:使用 Web Map Service (WMS) 协议,这是一种 OGC 标准,用于从分布式地理空间数据库请求地理区域的地图瓦片。
- TileMapServiceImageryProvider:使用 Tile Map Service (TMS) 协议,通过 REST 接口访问地图瓦片。瓦片可以通过Cesium ion或GDAL2Tiles生成。
- WebMapTileServiceImageryProvider:使用 OpenGIS Web Map Tile Service (WMTS) 协议,这是一种 OGC 标准,用于通过互联网提供预先生成并包含地理参考信息的地图瓦片。
- OpenStreetMapImageryProvider:访问 OpenStreetMap 的瓦片或其他 Slippy map tiles。可以通过多种方式 托管这些瓦片。
- BingMapsImageryProvider:使用 Bing Maps REST Services 访问瓦片。需要在 Bing Maps 门户网站 创建 Bing Maps 密钥。
- ArcGisMapServerImageryProvider:使用 Esri 的 ArcGIS Server REST API 访问由 ArcGIS MapServer 托管的瓦片。
- GoogleEarthEnterpriseMapsProvider:提供访问公司存储在 Google Earth Enterprise 服务器的影像。
- MapboxImageryProvider:使用 Mapbox API 访问瓦片。需要创建一个帐户并提供您的 访问令牌。
- SingleTileImageryProvider:从单个图像创建瓦片。
- UrlTemplateImageryProvider:创建自定义的瓦片方案。通过使用包含占位符的 URL 模板,从各种影像源请求地图瓦片。例如,TMS 的 URL 模板可以是 //path-to-tiles/{z}/{x}/{reverseY}.jpg。
- TileCoordinatesImageryProvider:通过在每个瓦片周围绘制边框并标记其级别、X 和 Y 坐标,展示地球在特定的瓦片方案中是如何被划分的。
跨域资源共享
作为一种安全措施,Web 浏览器会阻止 JavaScript 代码访问来自不同站点的图像数据(即跨域)。对于 WebGL 应用程序,如 CesiumJS,如果图像(在此情况下为影像瓦片)来自不同的主机名或端口,而服务器没有明确允许跨域访问的话,这些图像是不能作为纹理使用的。具体来说,服务器需要在 HTTP 响应中包含 跨域资源共享(CORS)头,以向浏览器声明这些图像可以被共享,允许其他站点读取其像素。
不幸的是,并非所有影像服务都支持 CORS。对于那些不支持 CORS 的服务,必须使用代理服务器,该代理服务器与托管您的应用程序在同一来源。通过使用代理服务器,Web 浏览器和 CesiumJS 客户端会认为这些瓦片来自同一个来源。要在影像提供程序中使用代理,可以在构造影像提供程序时使用 proxy 属性。
layers.addImageryProvider(
new Cesium.WebMapServiceImageryProvider({
url: new Cesium.Resource({
url: "/path/to/imagery",
proxy: new Cesium.DefaultProxy("/proxy/"),
}),
layers: [...]
})
);
如果您在托管公开可访问的影像数据,我们鼓励您按照 这里 的说明,启用 CORS 配置。
影像提供程序 vs. 影像图层
到目前为止,我们还没有明确区分影像提供程序和影像图层的区别。影像提供程序负责向特定的地图服务请求瓦片数据,而图层负责显示这些瓦片。也就是说:
- 影像提供程序(Imagery Provider):负责从特定的在线地图服务(例如 WMS、TMS、WMTS 或其他地图源)请求影像瓦片。它只是一个数据请求的接口,不负责数据的显示。
- 影像图层(Imagery Layer):负责将影像提供程序请求到的瓦片实际显示在地图上。图层可以用来调整显示效果,例如设置透明度、亮度、对比度等。
const layer = layers.addImageryProvider(imageryProvider);
是以下代码的简写形式:
const layer = new Cesium.ImageryLayer(imageryProvider);
layers.add(layer);
通常情况下,我们创建影像提供程序的主要目的是为了生成图层,以便能够在地图上显示影像瓦片,同时我们也可以使用图层的属性(如 show、alpha、brightness 和 contrast)来改变其外观(详细信息请参见 ImageryLayer)。而将影像提供程序和图层分离,我们可以实现职责分离。让影像提供程序只需关注数据的请求逻辑,而图层负责数据的显示逻辑。这种分离方式不仅提高了系统的可维护性,还使得编写新的影像提供程序更加简便高效。
影像图层集合(即上述示例中的 layers)决定了图层的绘制顺序。图层根据添加的先后顺序从下到上进行绘制。影像图层集合的操作类似于 Cesium 中的其他集合,使用函数如 add、remove 和 get。除此之外,还可以使用 raise、raiseToTop、lower 和 lowerToBottom 来重新排序图层,详细信息请参见 ImageryLayerCollection。
异步影像提供程序和错误处理
一些影像提供程序,例如 IonImageryProvider 和 BingMapsImageryProvider,需要通过异步 Web 请求来进行初始化。处理这个问题有两种方式:
第一种方法我们已经在上述所有示例中使用过。ImageryLayer.fromProviderAsync 是一个帮助函数,它在后台处理所有异步操作,使你的应用代码看起来和同步一样。
然而,如果你需要更细粒度的控制和更灵活的错误处理,可以使用 fromUrl 工厂函数来创建异步影像提供程序,例如:
let imageryProvider;
try {
// Blue Marble Next Generation July, 2004 imagery from NASA
imageryProvider = await Cesium.IonImageryProvider.fromAssetId(3845);
} catch(error) {
console.log(`There was an error while creating the imagery provider: ${error}`);
}
const imageryLayer = new Cesium.ImageryLayer(imageryProvider);
const viewer = new Cesium.Viewer("cesiumContainer", {
baseLayer: imageryLayer
});
资源
你可以在 Sandcastle 中查看关于影像图层的示例:
- Imagery Layers — 涵盖了本教程中的代码示例。
- Imagery Layers Manipulation — 展示如何叠加来自多个源的影像,并独立调整每个图层的透明度。
- Imagery Adjustment — 调整影像图层的亮度、对比度、伽马值、色调和饱和度
此外,还可以查看以下参考文档: