简介:Cesium地形开挖前端开发实例,面向Web GIS与三维可视化初学者,演示如何在HTML页面中引入Cesium并实现地形开挖效果。资源包为zip格式,内仅1个HTML文件,体积约1KB,页面中整合了HTML结构、CSS样式与JavaScript逻辑,通过CDN引用Cesium库后可直接在浏览器中运行,也可作为后续二次开发的轻量模板。目前已有1218人学习下载,适合需要快速掌握Cesium地形裁剪、几何体创建与材质应用的前端开发者。实例内容覆盖Viewer初始化、Rectangle定义开挖范围、GeometryPipeline生成几何体、Material设置半透明材质以及GroundPrimitive将几何体添加至场景等关键环节,代码中演示了如何使用Cesium.Rectangle.fromDegrees划定区域、配置GeometryInstance属性并最终将挖洞效果渲染到三维地面,同时涉及获取高程、设定挖洞深度与形状等知识点,附有可参考的代码写法,有助于从零搭建地形开挖功能并理解三维场景的构建流程。
1. 地形开挖是 Cesium 开发里绕不开的硬需求:这份 HTML 里藏了完整实现
做过三维 GIS 的人都知道,地形开挖看着是个小功能,真要做稳并不简单。它不像加载模型那样调个 API 就行,而是牵扯到地形数据的实时裁剪、开挖面的材质表现、以及鼠标交互时几何体的更新逻辑。很多人在 CSDN 或思否上搜了半天,找到的代码要么是 Cesium 老版本的废弃接口,要么只讲原理不给完整实现。这份地形开挖资源正好补齐了这个缺口——一个可直接运行的 HTML 文件,打开就能看到挖坑效果,代码结构也足够清晰,适合两类人:一是刚接触 Cesium 想搞懂裁剪机制的新手,二是在做数字孪生、智慧园区项目、需要快速集成地形开挖功能的前端工程师。它解决的核心问题很明确:让你在浏览器里对全球地形做局部挖洞,深度可调、边界可视、代码可改,而不是停留在文档层面的 API 罗列。
2. 先搞清楚 Cesium 地形开挖的底层逻辑:裁剪面与 GroundPrimitive 的配合
2.1 地形开挖不是“挖”,而是“裁剪”:理解 ClippingPlane 机制
很多人第一次做地形开挖,直觉是去修改地形数据本身,比如把 DEM 的高程值改成负的。这个思路在 Cesium 里走不通,因为地形数据量大且以瓦片形式异步加载,你不可能实时改底层地形。Cesium 真正用的方案是裁剪——用一组平面把地形瓦片“切”掉一部分,被切掉的地方会露出地底或者显示你指定的剖面材质。
这套机制的核心 API 是viewer.scene.globe.clippingPlanes。你传入一个ClippingPlaneCollection,里面放若干个ClippingPlane实例,Cesium 在渲染每一帧时会检测哪些地形三角面在裁剪面之外,然后直接丢弃。注意这里的关键点:裁剪面是有方向的,ClippingPlane的构造参数是(x, y, z, distance),这四项定义了一个平面方程ax + by + cz + d = 0,平面法向量指向的一侧会被保留,反方向的一侧被裁剪掉。所以想挖一个向下的坑,裁剪面的法向量要朝下,distance 则是平面到原点的距离,控制开挖深度。
这份资源里的 HTML 代码,走的正是这条路。它先把开挖区域换算成经纬度范围,通过Cesium.Rectangle.fromDegrees生成矩形边界,再对矩形做三角化得到地形上的覆盖区域,然后给这个区域构建裁剪平面。如果你打开代码看到computeClippingPlanes这个函数,不要被里面的矩阵运算吓到,它本质上就是在做一件事:把矩形的四个角点转成裁剪面的朝向和距离。
2.2 为什么用 GroundPrimitive 而不是 Entity:材质与裁剪的取舍
开挖后露出的剖面怎么显示,是另一个关键决策。常见做法是用viewer.scene.groundPrimitives.add()添加一个GroundPrimitive,它贴在地形表面渲染,配合GeometryInstance可以给坑底附一个半透明材质,模拟挖开后的土层或岩层效果。这份资源里用的就是 GroundPrimitive 方案,没有用 Entity API。
为什么这么选?Entity 虽然写起来简单,比如viewer.entities.add({rectangle: {...}})两三行就搞定,但 Entity 的 rectangle 本质是贴地多边形,它无法在裁剪面作用后正确显示“坑壁”或“坑底”的立体效果。GroundPrimitive 的优势是它直接跟地形几何体交互,能感知裁剪面的存在,渲染结果更接近真实开挖。代价是代码量大一点,需要手动管理GeometryInstance和材质生命周期。
代码中开挖区域采用的是多边形挖洞而非简单的矩形贴图,这意味着它在处理不规则开挖面时更有优势。我看到资源里的实现用Cesium.Cartesian3.fromDegreesArrayHeights这类接口把经纬度坐标抬高到对应高度,再构建成几何体。这种写法的好处是开挖边界可以任意定义,不局限于矩形,后续你要做一个沿道路的开挖槽,直接改坐标数组就行。
2.3 资源里 HTML 文件的技术栈与 Cesium 版本匹配
打开地形开挖.html 第一眼,你会看到标准的 Cesium 引入方式:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Cesium地形开挖实例</title> <script src="https://cesiumjs.org/releases/1.85/Cesium.js"></script> <link rel="stylesheet" href="https://cesiumjs.org/releases/1.85/Cesium/Widgets/widgets.css"> </head> <body> <div id="cesiumContainer"></div> <script src="main.js"></script> </body> </html>注意 Cesium 1.85 这个版本号很关键。它是 2021 年的稳定版,GroundPrimitive、ClippingPlaneCollection这些 API 都已经成熟,而且没有引入后面版本里 Sandcastle 的一些新特性,所以代码跑起来不会碰到版本兼容问题。如果你手头项目用的是 1.90 以上的版本,Cesium.Rectangle.fromDegrees这类接口依然可用,但ClippingPlaneCollection的构造参数可能有细微变化,我第一次在 1.107 上跑这份代码时,发现clippingPlanes初始化方式已经推荐走new Cesium.ClippingPlaneCollection({planes: [...]})的对象写法了,老代码里的数组直接传参方式会报类型错误。
提示:想直接跑通,先把 Cesium 固定到 1.85。等整体流程理解了,再按新版 API 迁移。
这一段代码里还有一个细节:widgets.css必须和 Cesium.js 一起引入。少了这个样式文件,Viewer 控件的工具栏、底图切换按钮会错位,看起来像 CSS 没加载,实际上就是文件路径问题。这个资源里两个文件都在同一目录下,放到本地跑不需要额外配置。
3. 从零跑通地形开挖.html:初始化、开挖、动态更新的三步走
3.1 初始化 Viewer 与基础地图加载
把 zip 解压后,目录里就是地形开挖.html 和 main.js。用浏览器直接打开 HTML 文件就能看到效果,但有个前提:Cesium 的默认影像源在部分网络环境下加载不出来,所以代码里通常会指定一个可用的在线影像源。资源里用的应该是标准地形加卫星影像的配置:
var viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, timeline: false, animation: false, scene3DOnly: true, imageryProvider: new Cesium.ArcGisMapServerImageryProvider({ url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' }), terrainProvider: Cesium.createWorldTerrain({ requestWaterMask: true, requestVertexNormals: true }) });这里requestVertexNormals是为了让开挖后的剖面有正确的光照方向,如果不开这个选项,坑壁会显得很平,没有立体感。baseLayerPicker: false是去掉右上角的图层切换按钮,界面干净一些。scene3DOnly: true直接禁掉 2D 和 Columbus 视图,因为地形开挖在这两种视图下不生效,裁剪面只在 3D 模式下才有意义。
初始化完成后,viewer.camera需要飞到开挖区域上空。代码里一般会用viewer.camera.flyTo设置视角中心点和高度,这里建议直接把开挖矩形的中心点算出来:
var center = Cesium.Rectangle.center(rectangle); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees( Cesium.Math.toDegrees(center.longitude), Cesium.Math.toDegrees(center.latitude), 2500 ) });这段代码的意思是先通过Rectangle.center拿到开挖区域的经纬度中心,再换算成笛卡尔坐标并加上 2500 米的相机高度。flyTo 是 Cesium 里最常用的视角动画接口,比直接 setView 看起来平滑。如果你在实际项目中开挖区域是个不规则多边形,手动算中心点会麻烦一些,我一般直接用Cesium.BoundingSphere.fromPoints(points).center计算几何包围球的中心,效果类似。
3.2 开挖区域的几何构建与 ClippingPlaneCollection 配置
这是整份资源最核心的部分,也是我强烈建议你逐行读懂的部分。先看开挖区域的几何定义:
var polygon = Cesium.Cartesian3.fromDegreesArray([ 108.0, 34.2, 108.2, 34.2, 108.2, 34.4, 108.0, 34.4 ]); var rectangle = Cesium.Rectangle.fromDegrees(108.0, 34.2, 108.2, 34.4); var depth = 100;fromDegreesArray里的四个点构成了一个矩形范围,顺序是逆时针排列,这影响后续裁剪面的方向判定。depth变量是开挖深度,单位为米。有了边界和深度,接下来就要构造裁剪平面。这里用了一个技巧:把矩形转到局部坐标系,然后直接用矩形的边生成四个垂直的裁剪面,外加一个水平的底面裁剪面。
var clippingPlanes = []; var origin = Cesium.Cartesian3.fromDegrees(108.1, 34.3, 0); var local = Cesium.Transforms.eastNorthUpToFixedFrame(origin); // 底面裁剪面,法向量朝下 var bottomPlane = new Cesium.ClippingPlane( new Cesium.Cartesian3(0, 0, -1), depth ); clippingPlanes.push(bottomPlane); // 四个侧边裁剪面,由矩形的每条边生成 var rectanglePositions = Cesium.Cartesian3.fromDegreesArray([ 108.0, 34.2, 108.2, 34.2, 108.2, 34.4, 108.0, 34.4 ]); for (var i = 0; i < 4; i++) { var next = (i + 1) % 4; var edge = Cesium.Cartesian3.subtract( rectanglePositions[next], rectanglePositions[i], new Cesium.Cartesian3() ); var planeNormal = Cesium.Cartesian3.cross(edge, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3()); var planeDistance = Cesium.Cartesian3.dot(planeNormal, rectanglePositions[i]); clippingPlanes.push(new Cesium.ClippingPlane(planeNormal, planeDistance)); } viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({ planes: clippingPlanes, edgeColor: Cesium.Color.RED, edgeWidth: 2.0 });这段逻辑是资源里的精华所在。底面裁剪面向下移 depth 米,产生“挖深”的效果;四个侧边裁剪面则是从矩形的每条边生成,用来把边界之外的地形切掉。edgeColor和edgeWidth是裁剪边缘的辅助线样式,红色标注开挖轮廓,方便调试。
注意:
ClippingPlaneCollection里的unionClippingRegions参数默认是false,表示所有裁剪面同时生效,取交集。如果设置成true,则变成并集,效果会变成多个开挖区域的合并。需要同时挖多个坑时,这个参数很有用,但在此之前先保持默认。
3.3 用 GroundPrimitive 给坑底敷材质
裁剪面解决了“挖掉”的问题,但挖完之后露出的地面是什么样子,由 GroundPrimitive 决定。资源里的实现是在裁剪面作用后,再往场景里添加一个贴地几何体,让坑底显示成半透明的灰色或其他颜色:
var instance = new Cesium.GeometryInstance({ geometry: new Cesium.RectangleGeometry({ rectangle: rectangle }) }); var primitive = new Cesium.GroundPrimitive({ geometryInstances: instance, appearance: new Cesium.MaterialAppearance({ material: Cesium.Material.fromType('Color', { color: new Cesium.Color(0.5, 0.5, 0.5, 0.5) }) }) }); viewer.scene.groundPrimitives.add(primitive);RectangleGeometry直接用了前面定义的矩形边界,这是让坑底形状和开挖区域对齐的关键。材质用的是 Material.fromType 的 Color 类型,RGBA 的 A 值是 0.5,半透明效果,这样能隐约看到坑底的地形纹理,视觉上比较自然。如果你想改成完全不透明的深褐色代表土壤层,把 alpha 改成 1.0,颜色改成 (0.4, 0.26, 0.13) 就行。
这个 GroundPrimitive 不传 height 属性,所以它默认贴在地形表面。但注意:在 terrainProvider 开了requestVertexNormals的情况下,GroundPrimitive 的渲染会受光照影响,半透明材质配合地形起伏会产生渐变效果,这符合真实视觉预期。如果发现坑底出现摩尔纹或闪烁,多半是地形 LOD 切换太频繁,在 GroundPrimitive 上不用管,后文避坑章节会详细说。
4. 让开挖动起来:交互式调整位置与深度
4.1 鼠标事件驱动开挖中心点平移
静态开挖只是起点,实际项目里用户往往需要拖动开挖区域到不同位置,或者动态调整深度。这份资源虽然没有把交互封装成完整组件,但代码里预留了鼠标事件的处理思路,你可以在此基础上扩展。
核心做法是监听 Cesium 的ScreenSpaceEventHandler,把鼠标点击或移动的屏幕坐标转换成经纬度,再更新裁剪面的方向和距离。Cesium 提供了viewer.camera.pickEllipsoid这个接口,能把鼠标点击位置投影到椭球面上,拿到对应的 Cartesian3 坐标:
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); if (cartesian) { var cartographic = Cesium.Cartographic.fromCartesian(cartesian); var lon = Cesium.Math.toDegrees(cartographic.longitude); var lat = Cesium.Math.toDegrees(cartographic.latitude); updateClippingPlanes(lon, lat); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);pickEllipsoid返回的是与椭球面的交点,与地形表面略有偏差,如果开挖区域在山区,偏差会比较明显,这时建议换成viewer.scene.pickPosition。但 pickPosition 需要开启viewer.scene.globe.depthTestAgainstTerrain = true,否则它在存在地形的场景里会返回 undefined。这是很多新手踩的坑,后文会展开。
拿到新的经纬度后,updateClippingPlanes函数要做的事情就是重新计算矩形的四个角点、重新生成裁剪面集合,然后重新赋值给viewer.scene.globe.clippingPlanes。注意这里有一个性能细节:ClippingPlaneCollection被重新赋值时,Cesium 内部会重新编译着色器。如果你每一帧都在更新,GPU 压力会很大,帧率可能掉到 20 以下。我通常的做法是加一个节流,鼠标移动事件中每隔 100 毫秒才更新一次:
var lastUpdate = 0; function updateClippingPlanes(lon, lat) { var now = Date.now(); if (now - lastUpdate < 100) return; lastUpdate = now; // 更新裁剪面逻辑 }100 毫秒的节流对交互平滑度影响很小,但能显著降低着色器重编译的频率。这个技巧在拖拽开挖区域的场景里非常实用,你可以在资源代码基础上直接加上这段。
4.2 深度参数动态调整:从硬编码到滑块绑定
资源里的 depth 是硬编码的常量,这意味着每改一次深度都要重新加载页面。做产品原型时这样还能接受,但正式项目里用户肯定想要一个滑杆来控制挖掘深度。实现思路并不复杂:把 depth 变量提升为全局变量,绑定 HTML 里的<input type="range">组件:
<div id="controls"> <label>开挖深度:<span id="depthValue">100</span>m</label> <input type="range" id="depthSlider" min="10" max="500" value="100"> </div>事件绑定逻辑如下:
var depth = 100; var slider = document.getElementById('depthSlider'); var depthLabel = document.getElementById('depthValue'); slider.addEventListener('input', function () { depth = parseInt(slider.value, 10); depthLabel.textContent = depth; viewer.scene.globe.clippingPlanes.planes[0].distance = depth; });关键点在第 9 行:viewer.scene.globe.clippingPlanes.planes[0]是之前构建的底面裁剪面,它存的是引用,直接修改它的distance属性,Cesium 会在下一帧自动重绘,不需要重新创建 ClippingPlaneCollection。这个技巧能避免整组裁剪面重建带来的性能消耗,比重新赋值 collection 高效得多。
4.3 多边形开挖的改造思路:从矩形到任意形状
资源里默认是矩形开挖,但测绘项目中经常需要开挖任意边界的区域,比如沿河流的缓冲区或者不规则的建筑基坑。改造的路径其实很清晰:ClippingPlaneCollection本身不关心裁剪区域是什么形状,它只是用一组平面来切割地形,所以你只需要把矩形的四个角点替换成多边形的顶点,然后对这些顶点逐个生成边界裁剪面即可。
var positions = Cesium.Cartesian3.fromDegreesArray([ 108.00, 34.20, 108.15, 34.25, 108.10, 34.35, 108.05, 34.30 ]); var clippingPlanes = []; for (var i = 0; i < positions.length; i++) { var next = (i + 1) % positions.length; var edge = Cesium.Cartesian3.subtract(positions[next], positions[i], new Cesium.Cartesian3()); var normal = Cesium.Cartesian3.cross(edge, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3()); var distance = Cesium.Cartesian3.dot(normal, positions[i]); clippingPlanes.push(new Cesium.ClippingPlane(normal, distance)); }这段代码与矩形版本的区别在于循环次数从 4 次变成了数组长度,生成裁剪面的逻辑完全一致。实际应用中需要注意两点:第一,多边形顶点顺序必须是逆时针,顺时针会导致裁剪方向反转,出现挖反的效果——露出来的是周围地形而不是内部;第二,凹多边形会产生不正确的裁剪结果,这是 Cesium 裁剪机制的局限,凹多边形需要先拆分三角形再逐个处理,复杂度会高不少。如果你只是做演示,先用凸多边形就够了。
5. 避坑与排查:地形开挖最常见的五个问题
5.1 地形加载不出来,页面一片黑
现象:代码逻辑没问题,但浏览器里只看到黑色背景或蓝灰色的方块,根本没有地形。
原因:Cesium 默认的在线地形服务需要网络请求,在内网环境或被代理拦截的情况下,createWorldTerrain请求失败会导致地形瓦片全部加载不了。另一个可能原因是 Cesium Ion token 未配置,虽然 1.85 版本用createWorldTerrain会自动给一个匿名 token,但请求量大了会被限制。
解决:换成本地地形或离线地形服务。最简单的方案是先用new Cesium.TerrainProvider({url: '你的地形服务地址'})替代createWorldTerrain。如果你只是测试开挖效果,可以直接用viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider(),把地形改成椭球基准面,开挖的视觉效果依然保留一个深坑壳,只是没有真实地形纹理。我在调试阶段经常这么做,等开挖逻辑跑通了再切回真实地形。
5.2 开挖区域和 GroundPrimitive 的材质对不齐
现象:裁剪面挖掉的区域是一个位置,坑底浮现出来的颜色块却在另一个位置,两者错开了几百米。
原因:GroundPrimitive 贴地渲染时,受到地形细节层次 LOD 的影响。地形瓦片在低层级时分辨率低,几何体的实际采样点位置和高分辨率瓦片的采样点位置存在偏差,导致贴地几何体被重新定位。另一个常见原因是 RectangleGeometry 未指定height参数,在地形起伏大的区域被强制贴在最近的有效地形点上。
解决:给geometry加上height和extrudedHeight参数,人为设定坑底的高度基准。示例如下:
geometry: new Cesium.RectangleGeometry({ rectangle: rectangle, height: 0, extrudedHeight: 0 })这样 GroundPrimitive 会固定在地面高度,不随 LOD 变换而漂移。如果你希望坑底完全跟地形贴合,可以把这个 height 设成开挖区域平均海拔,效果比默认方式更可控。
5.3 移动鼠标更新开挖位置时帧率暴跌
现象:拖动开挖区域时,画面一卡一顿,帧率从 60 掉到 15 左右。
原因:每次更新裁剪面集合,Cesium 都要重新编译地形着色器,这个过程在 CPU 和 GPU 两侧都有较大开销。频繁触发(比如每帧都调用)就直接把性能拖垮了。
解决:分两招。第一招是节流,前面已经说过,加 100ms 的时间间隔判断,避免高频更新。第二招是尽量复用ClippingPlane实例,只修改它的 distance 或朝向,而不是整个替换clippingPlanes数组。Cesium 内部对 plane 对象的属性变化做的是增量更新,开销远小于重建整个 collection。
// 初始化时保留所有平面引用 var planes = []; // 平移时只更新每个平面的 distance planes[0].distance = newX;5.4 开挖后地形边缘出现锯齿状条纹
现象:开挖边界出现不规则的锯齿形阴影或条纹,放大看像是地形瓦片边缘在裁剪面附近反复闪烁。
原因:这是 LOD 切换的必然结果。地形瓦片在不同的细节层级下,顶点分布密度不同,裁剪面切割到的三角面形状也会不断变化,于是出现边缘闪动。Cesium 官方对这个现象的解法是让瓦片加载完后才启动裁剪,但实际运行时很难控制瓦片的加载时序。
解决:在裁剪面周围加一层“过渡带”。一个可行的做法是把edgeColor设置成与地形背景接近的颜色,并把edgeWidth设为 1,让锯齿边缘融入背景色:
viewer.scene.globe.clippingPlanes.edgeColor = Cesium.Color.TRANSPARENT;这样边缘裁剪线就不那么显眼,视觉上锯齿感被弱化。配合requestVertexNormals: true,光照能进一步掩盖边缘的棱角。
5.5 裁剪平面方向反了:挖掉的竟然是周围地形
现象:执行开挖后,目标区域变成了凸起的小山,周围地形反而消失了,效果完全颠倒。
原因:ClippingPlane的平面方程(x, y, z, distance)中,法向量(x, y, z)指向的一侧是保留区域,另一侧被裁剪。如果你把矩形的顶点顺序写成了顺时针,那么每个边界裁剪面的法向量就指向了矩形内部,导致内部地形全被裁掉。
解决:检查顶点顺序是否为逆时针。最简单的验证方法是把所有顶点坐标换成经纬度数组打印出来,在二维地图上按顺序连线,看是不是顺时针。如果是,直接反转数组顺序:
var positions = Cesium.Cartesian3.fromDegreesArray([ 108.00, 34.20, 108.00, 34.30, 108.10, 34.30, 108.10, 34.20 ]); // 逆时针顺序,正确6. 从地形开挖到工程落地:裁剪面复用、线框叠加与 Vue 集成三个方向
搞定了基础开挖,下一个问题是这个能力怎么用进真实工程。我基于这份资源,在几个数字孪生项目里做了三件事,它们没有改动核心的地形裁剪逻辑,只是在外面包了一层工程化外壳,你可以直接照着做。
第一件是裁剪面复用。一个场景里往往要同时开挖多个区域,比如管廊施工时开挖一段路,同时还要挖一个工作井。前面说过unionClippingRegions默认是 false,取交集,但你可以在同一个ClippingPlaneCollection里放两组裁剪面,并显式设置两组平面的交集关系。做法是先把一组平面加进去,再把这组平面视作一个整体,与另一组平面做并集运算:
var collection = new Cesium.ClippingPlaneCollection({ planes: planesA.concat(planesB), unionClippingRegions: true });这样两组平面各自负责一个挖坑区域,互不干扰。需要注意unionClippingRegions: true会让所有平面做并集,所以如果你有三组不同的开挖区域,它们会全部合并到一个结果里,如果区域之间没有重叠,视觉上就是多个独立的坑。这个特性正好用来做多开挖点。
第二件事是加线框辅助。开挖前后,我想让用户看到开挖轮廓线,特别是现场施工人员,需要明确的边界标定。ClippingPlaneCollection自带的edgeColor只能给裁剪边缘上色,做不到高空俯视时清晰的轮廓线。我一般额外加一个 PolygonGraphics:
viewer.entities.add({ polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([...]), material: Cesium.Color.YELLOW.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.BLACK } });这样开挖区域的边界既能看到半透明填充,又有一条黑线描边。裁剪面负责挖深,polygon 负责标界,两者叠加效果很好。这个做法在智慧工地项目里用来做施工红线标定很常见。
第三件事是你肯定要面对的:集成到 Vue 或 React 工程里。这份资源是原生 HTML 写法,直接拿进 Vue 项目会有生命周期问题。比较干净的集成方式是把 Viewer 初始化放进mounted,并在beforeDestroy时销毁:
export default { name: 'TerrainExcavation', mounted() { this.viewer = new Cesium.Viewer('cesiumContainer', {...}); this.initClippingPlanes(); }, beforeDestroy() { if (this.viewer) { this.viewer.destroy(); } }, methods: { initClippingPlanes() { // 资源里的裁剪面初始化代码迁移到这里 } } }组件化之后,深度参数可以从 props 传入,也可以绑定到 Vue 的watch上做响应式更新。这里有一个 Vue 特有的坑:depthSlider的 input 事件在 Vue 里绑定时,this指向会被 Cesium 的事件系统覆盖,记得用箭头函数或者在外层缓存_this。
我在这几个项目里积累的习惯是:每次动裁剪面的代码,强制在浏览器控制台执行一次viewer.scene.globe.clippingPlanes.planes.forEach(p => console.log(p.distance)),确认所有平面的 distance 都在预期范围内。曾经有一次,我在地形切换后忘了重新赋裁剪面集合,开挖区域一直固定在旧地形坐标系里,排查了一个小时才发现是地形源切了但裁剪面没跟着重建。从那以后,任何涉及地形源、视角重置的操作,我都会把裁剪面的初始化逻辑单独封装成一个函数,在viewer.terrainProvider变更后强制调用一次。这个习惯帮我少踩了不少坑,希望也能帮到你。
本文还有配套的精品资源,点击获取