CesiumJS 地下场景可视化:管线展示、切剖查看与点击查询
【免费下载链接】cesiumAn open-source JavaScript library for world-class 3D globes and maps :earth_americas:项目地址: https://gitcode.com/GitHub_Trending/ce/cesium
当管线数据需要在地面以下呈现时,核心矛盾只有一条深度线:哪些像素在前、哪些在后。CesiumJS 是基于 WebGL 的三维地球引擎,提供地形、3D Tiles 与深度测试控制,用于搭建 Cesium 地下场景并完成管线三维展示。本文用三个子任务走通一条地下管网的完整流程。
能力边界:地下可视化能做什么、不能做什么
CesiumJS 的渲染走 WebGL 光栅化管线,场景里所有图层共用一张深度缓冲。这意味着地下物体与地表地形的遮挡关系不是"贴"上去的特效,而是由深度值自动裁决的。具体能力:
- 地形按高程瓦片加载,地表会正确遮挡地面以下的几何体,这是深度测试的默认行为;
- 3D Tiles 支持显式开启
depthTestAgainstTerrain,让地下对象参与地形深度测试,切剖后的管线不会浮在切面上; - 实体支持
HeightReference.BELOW_GROUND,点、标注可以直接沉到地表之下; - 裁剪区域与裁剪平面可切掉部分地表或模型,露出地下结构;
- 拾取与元数据查询可以定位到单个管线特征。
局限同样直白:它是光栅化引擎,不是 BIM 内核。十万级管线、带完整材质的大体量城市模型会撞上帧率上限;地层剖面、地质建模它一概不管,属于数据生产侧的工作,引擎只负责把已经算好的几何画出来。
任务实战:搭出一个地下管网场景
先建场景,并把相机行为调到适合地下的参数。
const viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain(), baseLayerPicker: false, geocoder: false, sceneModePicker: false, homeButton: false }); // 关掉碰撞检测,相机才能穿过地表进入地下 viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; viewer.scene.globe.depthTestAgainstTerrain = true;enableCollisionDetection = false让鼠标拖动不再被地形顶住,相机能直接穿到地表之下;globe.depthTestAgainstTerrain = true让地表参与深度测试,地面正确挡住地下的物体。
加载管线与地质数据:用 3D Tiles 让引擎管 LOD。
const tileset = viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: 'data/pipeline-network/tileset.json', depthTest: true, depthTestAgainstTerrain: true }) ); // 地质剖面用实体画在地面以下 viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.4, 39.9, -15), box: { dimensions: Cesium.Cartesian3.fromElements(300, 4, 300) }, heightReference: Cesium.HeightReference.BELOW_GROUND, material: Cesium.Color.rgb(255, 180, 0).withAlpha(0.35) });depthTestAgainstTerrain: true是关键:地形被切剖后,切面下方的管线会被切面正确遮挡,而不是整条管线"浮"在剖面上。此时深度测试已经在替你处理"谁在前谁在后",不需要任何手工排序。3D Tiles 还按距离和视锥自动切换瓦片细节等级,远处瓦片降精度、近处瓦片高细节,这一层 LOD 引擎内置,不用自己写。
加点击查询:选中一条管线就查它。
viewer.screenSpaceEventHandler.setInputAction(function (movement) { const picked = viewer.scene.pick(movement.position); if (!Cesium.defined(picked) || !picked.id) { return; } const entity = picked.id; console.log('选中对象:', entity.name, '材质:', entity.propertyBag?.material ?? '未标注'); viewer.zoomTo(entity); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);scene.pick返回深度最靠前的对象,propertyBag里放管线台账字段(材质、管径、埋深),命中后直接打印或回填到查询面板。如果管线特征带元数据,可以用tileset.metadata的属性表达式做条件着色与筛选,比全量实体拾取省内存。
性能技巧:问题、手段与效果
| 问题 | 手段 | 效果 |
|---|---|---|
| 城市级管线一次全量加载 | 数据切成 3D Tiles 瓦片,交给引擎按距离、视锥调度 | 只有视口附近的瓦片驻留显存,内存随视角伸缩 |
| 阀门、井盖等大量重复小构件 | 用 3D Tiles 实例化或合并几何,减少 draw call | 绘制调用显著减少,帧率更稳 |
| 多层管线同深度叠加、画面闪烁 | 用裁剪区域切剖展示,代替同层叠加 | 避免深度冲突,画面稳定 |
| 二进打开场景加载慢 | 依赖瓦片 HTTP 缓存,首访后走缓存 | 二次打开明显变快 |
常见误区
- 以为地下不可见是材质问题。实际是浮点深度精度有限:地形面与管线在同一深度带时,深度缓冲区分不了两者,表现为闪烁。处理上不要用同层叠加,改用裁剪区域切掉一块地表做剖视,或者让不同埋深的管线各占一个深度带。
- 把所有管线塞进一个数据源全量加载。内存膨胀、渲染线程卡死。按 3D Tiles 切瓦片,引擎自动管理细节等级;自建几何也要按区域分块,进入视口才加入场景。
- 对碰撞检测一刀切。开着它,相机贴着地形时根本进不去地下;关掉后相机又能穿到球体内部出不来。地下场景通常关掉它,再用
scene.maximumCameraHeight之类参数把上界收住。 - 用
tileset.show做筛选。全量开关不解决"选中哪几根管线"的问题。正确做法是用元数据属性表达式过滤和着色,或者把常变的管线状态放到独立的轻量数据源里。
下一步
官方 API 文档见 Documentation/,其中裁剪、3D Tiles 元数据等条目与本文流程直接对应。可运行的同类示例在 Sandcastle 示例库 里,重点看 clipping-regions(裁剪地表切剖)、splitdirection(分屏对比视角)与 3d-tiles 系列(元数据筛选、深度测试)。数据侧再往深走,可以把管线台账接入 3D Tiles 的 metadata 字段,让筛选、统计和着色都走元数据表达式,而不是维护大量实体。
【免费下载链接】cesiumAn open-source JavaScript library for world-class 3D globes and maps :earth_americas:项目地址: https://gitcode.com/GitHub_Trending/ce/cesium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考