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 砸单。首单合作,价格好商量,保质保量交朋友!

相关推荐
Mr_Mao18 小时前
告别选型困难!集 VueUse、ahooks、Mantine 于一身:286 个 Hook 的 ReaUse 来了
前端·javascript·react.js
李游Leo18 小时前
《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》02:世界坐标、局部坐标与Transform空间变换【鸿蒙心迹】
3d·harmonyos
qwfy19 小时前
我要用 AI-native 架构,从零重建一套制造业 ERP/MES
vue.js·spring boot·架构
默_笙19 小时前
🚙 一条腿走路会摔:ES 关键词检索、混合召回与 ReRank 裁判
前端·javascript
dsyyyyy110119 小时前
Vue 3 Watch 监视完全指南
前端·javascript·vue.js
瞬时出道20 小时前
AI 回答为什么能一个字一个字蹦出来?前端搞懂 SSE 这一篇就够了
vue.js
u0111026751 天前
Vue 3 实现图片裁剪框:拖动、缩放与固定宽高比
前端·javascript·vue.js
DcMedia元宇宙1 天前
谁能登上「数字化」的「诺亚方舟」
web3·数字化
小小善后师1 天前
用 Canvas + AI 实现登录页的 Logo 粒子动画
前端·vue.js
木西1 天前
从 “跑鞋” 到实体卡牌藏品:户外 AR 互动游戏 GoCollect,产品架构全景解析
web3·智能合约·solidity