You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CesiumJS中能否调整3D地形高程?含自定义实现问题

CesiumJS地形高程操纵问题解答

一、CesiumJS支持的地形高程操纵能力

CesiumJS完全支持地形高程调整,涵盖高程夸张和局部地形平整这类需求:

  • 高程夸张:可通过修改地形提供者参数或自定义逻辑实现全局/局部的高程缩放。
  • 局部地形平整:需通过自定义瓦片处理或修改地形网格顶点数据实现,但要注意避免地形衔接异常引发的视角问题。

二、自定义瓦片提供者平整地形导致视角异常的解决思路

你遇到的视角异常,大概率是修改地形顶点高程时,未同步处理Cesium内部的地形LOD(细节层次)计算或瓦片边界衔接。可以尝试以下方案:

  1. 限制修改范围并做平滑过渡:仅在目标红色矩形区域内修改高程,边界处逐步过渡高程值,避免相邻瓦片高程突变。
  2. 确保瓦片数据状态正确:重写地形瓦片的getTileDataAvailable方法,让Cesium能正确识别修改后的瓦片数据,避免加载异常。
  3. 通过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的内置功能,示例如下:

  1. 添加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>
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 08:53:24