CesiumJS中能否调整3D地形高程?含自定义实现问题
CesiumJS地形高程操纵问题解答
一、CesiumJS支持的地形高程操纵能力
CesiumJS完全支持地形高程调整,涵盖高程夸张和局部地形平整这类需求:
- 高程夸张:可通过修改地形提供者参数或自定义逻辑实现全局/局部的高程缩放。
- 局部地形平整:需通过自定义瓦片处理或修改地形网格顶点数据实现,但要注意避免地形衔接异常引发的视角问题。
二、自定义瓦片提供者平整地形导致视角异常的解决思路
你遇到的视角异常,大概率是修改地形顶点高程时,未同步处理Cesium内部的地形LOD(细节层次)计算或瓦片边界衔接。可以尝试以下方案:
- 限制修改范围并做平滑过渡:仅在目标红色矩形区域内修改高程,边界处逐步过渡高程值,避免相邻瓦片高程突变。
- 确保瓦片数据状态正确:重写地形瓦片的
getTileDataAvailable方法,让Cesium能正确识别修改后的瓦片数据,避免加载异常。 - 通过
requestTileGeometry钩子修改顶点:在获取地形几何数据后,针对性调整目标区域的顶点高程,示例代码如下:
const customTerrainProvider = new Cesium.CesiumTerrainProvider({ url: 'https://assets.agi.com/stk-terrain/world', // 3D World Terrain地址 }); // 重写requestTileGeometry方法 const originalRequestTileGeometry = customTerrainProvider.requestTileGeometry; customTerrainProvider.requestTileGeometry = function(x, y, level, request) { return originalRequestTileGeometry.call(this, x, y, level, request).then(function(geometry) { if (!geometry) return geometry; // 定义目标红色矩形的经纬度范围(示例:旧金山南部区域) const targetRect = Cesium.Rectangle.fromDegrees(-122.5, 37.6, -122.3, 37.8); // 获取当前瓦片的覆盖范围 const tileRect = Cesium.TerrainProvider.getTileRectangle(level, x, y); // 仅在瓦片与目标区域重叠时修改高程 if (Cesium.Rectangle.intersect(targetRect, tileRect)) { const positions = geometry.attributes.position.values; for (let i = 0; i < positions.length; i += 3) { const cartographic = Cesium.Cartographic.fromRadians(positions[i], positions[i + 1]); // 判断当前点是否在目标矩形内 if (Cesium.Rectangle.contains(targetRect, cartographic)) { positions[i + 2] = 0; // 将高程设为0,实现平整 } } } return geometry; }); }; viewer.terrainProvider = customTerrainProvider;
注意:这种方式会增加地形加载的计算量,建议结合地形LOD级别做优化,比如只在低级别瓦片执行平整逻辑,高级别瓦片跳过以保证性能。
三、给3D World Terrain添加高程夸张滑块
可以参考3D Tiles垂直夸张的实现逻辑,通过自定义地形提供者的高程缩放来实现,无需依赖Cesium World Bathymetry的内置功能,示例如下:
- 添加HTML滑块控件:
<input type="range" id="heightExaggerationSlider" min="0.1" max="10" step="0.1" value="1"> <label for="heightExaggerationSlider">高程夸张倍数:<span id="exaggerationValue">1</span></label>
- CesiumJS中实现高程缩放逻辑:
let heightExaggeration = 1; const customTerrainProvider = new Cesium.CesiumTerrainProvider({ url: 'https://assets.agi.com/stk-terrain/world', }); // 重写requestTileGeometry实现全局高程夸张 const originalRequestTileGeometry = customTerrainProvider.requestTileGeometry; customTerrainProvider.requestTileGeometry = function(x, y, level, request) { return originalRequestTileGeometry.call(this, x, y, level, request).then(function(geometry) { if (!geometry) return geometry; const positions = geometry.attributes.position.values; // 缩放所有顶点的高程值 for (let i = 0; i < positions.length; i += 3) { positions[i + 2] *= heightExaggeration; } return geometry; }); }; viewer.terrainProvider = customTerrainProvider; // 绑定滑块事件,实时更新夸张倍数并刷新地形 const slider = document.getElementById('heightExaggerationSlider'); const valueDisplay = document.getElementById('exaggerationValue'); slider.addEventListener('input', function(e) { heightExaggeration = parseFloat(e.target.value); valueDisplay.textContent = heightExaggeration.toFixed(1); viewer.scene.globe.refreshTerrain(); });
如果需要同时实现局部平整和全局高程夸张,只需在修改顶点时增加区域判断:
// 示例:局部区域平整,其他区域应用高程夸张 if (Cesium.Rectangle.contains(targetRect, cartographic)) { positions[i + 2] = 0; // 平整区域设为固定高程 } else { positions[i + 2] *= heightExaggeration; // 其他区域应用夸张倍数 }
内容的提问来源于stack exchange,提问作者guest_310723
相关产品推荐
相关产品推荐

