Cesium实现“悬浮岛”式,三维立体的行政区划

在 WebGIS 可视化项目中,我们经常遇到一类高频需求,重点展示特定行政区划,并隐藏全球其他无关区域

本文将深入探讨如何利用 Cesium 原生 API ClippingPolygon 实现真正的地形反向裁剪最终构建一个具有科技感的沉浸式地图场景。

1. 核心技术方案概览

实现该效果主要包含三个关键技术点:

  1. 地形反向裁剪(Inverse Clipping) :利用 ClippingPolygonCollection 将非目标区域的地形完全剔除,实现"挖空"效果。

  2. 环境透明化(Scene Translucency):配置 Viewer 场景属性,使地球球体透明,从而露出底层的背景。

  3. 深度检测与遮挡(Depth Testing & Occlusion):开启深度测试,确保地下的边界墙体被地表正确遮挡,消除视觉杂乱。


2. 场景初始化与透明化处理

为了让地球"悬浮"在我们的网页背景(CSS Background)之上,首先需要剥离 Cesium 默认的天空盒、大气层以及地球底色。

javascript 复制代码
// 初始化 Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
  // ...基础配置
  contextOptions: {
    requestWebgl2: true // 建议开启 WebGL2 以获得更好的性能和渲染效果
  }
});

// 核心配置:移除默认环境元素
viewer.scene.skyBox.show = false;       // 隐藏天空盒
viewer.scene.sun.show = false;          // 隐藏太阳
viewer.scene.moon.show = false;         // 隐藏月亮
viewer.scene.skyAtmosphere.show = false;// 隐藏大气层

// 开启地球透明支持
viewer.scene.globe.translucency.enabled = true; 
viewer.scene.globe.baseColor = Cesium.Color.TRANSPARENT; // 地球基底颜色设为全透
viewer.scene.backgroundColor = Cesium.Color.TRANSPARENT; // 场景背景色设为全透

3. 实现地形反向裁剪 (Inverse Clipping)

Cesium 的 ClippingPolygon 类允许开发者定义裁剪区域。默认情况下,裁剪是"保留外部,剔除内部"。但在本案例中,我们需要保留中国区域,剔除世界其他区域,因此需要启用 反向裁剪(Inverse)

3.1 数据转换:GeoJSON 转 ClippingPolygon

我们需要解析 GeoJSON 数据,提取每个省份多边形的边界坐标(Positions),并实例化为 ClippingPolygon 对象。

javascript 复制代码
async function applyGlobalClipping(geojsonData) {
  const dataSource = await Cesium.GeoJsonDataSource.load(geojsonData);
  const entities = dataSource.entities.values;
  const clipPolygons = [];

  entities.forEach(entity => {
    if (entity.polygon) {
      const hierarchy = entity.polygon.hierarchy.getValue();
      // 将边界坐标转换为 ClippingPolygon
      clipPolygons.push(new Cesium.ClippingPolygon({
        positions: hierarchy.positions
      }));
    }
  });

  // 应用裁剪集合
  viewer.scene.globe.clippingPolygons = new Cesium.ClippingPolygonCollection({
    polygons: clipPolygons,
    enabled: true,
    inverse: true // 【关键】设置为 true,表示保留多边形内部,裁剪外部
  });
}

此时地球上除了中国区域的地形和影像,其余部分已被完全剔除,露出了网页底部的 DOM 背景。

4. 边界渲染与深度冲突解决

为了增强视觉效果,通常会沿着边界生成发光线条(Polyline)和向下延伸的光墙(Wall)。然而,直接添加 Wall 实体会导致一个严重的渲染问题,由于墙体延伸至地下深处,在某些视角下,地下的墙体会透过地表显示出来,导致画面杂乱无章。

4.1 开启深度测试 (Depth Test)

这是解决"透视"问题的核心。默认情况下,Cesium 可能不会对地形以下的物体进行严格的遮挡计算。我们需要强制开启针对地形的深度检测。

javascript 复制代码
// 【核心代码】开启地形深度检测
// 作用:如果一个像素点位于地形表面之下,则不进行绘制。
// 这确保了我们向下延伸的 Wall 只有露出地表的部分可见,内部复杂的网格被完美遮挡。
viewer.scene.globe.depthTestAgainstTerrain = true;

4.2 构建渐变光墙与发光边界

在解决了遮挡关系后,我们可以放心地添加视觉元素。

  • 发光边界 :使用 PolylineGlowMaterialProperty 实现流光效果。

  • 渐变光墙 :使用 WallGraphics 配合动态生成的 Canvas 渐变纹理,实现从地表向下渐隐的科技感帷幕。

javascript 复制代码
// 示例:在遍历 GeoJSON 实体时同步添加视觉边界
viewer.entities.add({
  polyline: {
    positions: positions,
    width: 3,
    material: new Cesium.PolylineGlowMaterialProperty({
      glowPower: 0.2,
      color: Cesium.Color.CYAN.withAlpha(0.8)
    }),
    clampToGround: true // 贴地线
  }
});

viewer.entities.add({
  wall: {
    positions: positions,
    // 设置墙体高度范围:从地下 500km 到 地表 0m
    minimumHeights: new Array(positions.length).fill(-500000),
    maximumHeights: new Array(positions.length).fill(0),
    material: new Cesium.ImageMaterialProperty({
      image: createGradientCanvas(), // 辅助函数生成的线性渐变 Canvas
      transparent: true
    })
  }
});

注意事项ClippingPolygon 的性能开销与多边形的顶点数量及多边形个数成正比。如果加载过于破碎的行政区划(如包含大量岛屿的详细数据),可能会导致帧率下降或 WebGL 上下文丢失。在生产环境中,建议对 GeoJSON 进行简化处理,仅使用外轮廓数据进行裁剪。

关于作者 & 合作

感谢阅读!我是专注于 WebGIS 前端可视化 的独立开发者。

如果你的团队正在做 智慧城市、数字孪生、流域监测 等项目,却苦于没有专业的 GIS 前端支持,或者需要快速输出高质量的 2D/3D 地图效果,欢迎联系我。

  • 核心技术栈: Vue3 / React + Mapbox / Cesium / Three.js + Springboot/FastAPI + PostgreSQL/PostGIS

  • 服务范围: WebGIS 项目整包开发、复杂地图交互实现。

目前已成立个人工作室、公司。可公对公,可开发票。

相比于找昂贵的大型外包公司,我能提供更灵活的沟通更高的性价比。无论是几十个页面的管理大屏,还是一个核心的地图功能模块,我都会像对待自己的产品一样打磨细节。

手头目前有档期,欢迎各位老板、PM 砸单。首单合作,价格好商量,保质保量交朋友!

相关推荐
Up九五小庞11 分钟前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源
摘星编程34 分钟前
React Native + OpenHarmony:UniversalLink通用链接
javascript·react native·react.js
qq_177767371 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头88211 小时前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
程序员清洒3 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6663 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
会飞的战斗鸡4 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling4 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
qq_177767374 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767374 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体