You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Cesium中GeoJSON标记的标签定位问题

解决Cesium中ClampToGround标签被地形遮挡的问题

我完全懂你遇到的这个糟心问题——把GeoJSON点标记设为clampToGround: true后,标签在视图放大时就会“钻”到地形或建筑下面,这其实是Cesium的属性继承机制在搞鬼:当你给数据源开启clampToGround,实体的位置会被强制贴地,而标签默认会继承这个高度参考(heightReference),导致标签也死死贴在地面上,视角拉近时自然就被遮挡了。

下面是两种直接有效的解决方法,改改你的代码就能生效:

方法一:给标签单独设置高度参考与偏移

这是最省心的方案,只需要在创建LabelGraphics时,强制让标签脱离贴地设置,悬浮在标记上方:

const viewer = new Cesium.Viewer('cesiumContainer', {
  terrainProvider: Cesium.createWorldTerrain(),
  timeline: false,
  animation: false,
});

const buildingTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());

viewer.camera.flyTo({
  destination : Cesium.Cartesian3.fromDegrees(11.952996, 57.671910, 400),
  orientation : {
    heading : Cesium.Math.toRadians(0.0),
    pitch : Cesium.Math.toRadians(-15.0),
  }
});

const promise = Cesium.GeoJsonDataSource.load('data/botaniska_play.geojson', {
  clampToGround: true,
  markerColor: Cesium.Color.DARKGREEN,
});

promise.then(function (dataSource) {
  viewer.dataSources.add(dataSource);
  // 用官方API访问实体集合,别碰私有属性(带下划线的字段),避免版本更新崩代码
  const entities = dataSource.entities.values;
  for (const entity of entities) {
    entity.label = new Cesium.LabelGraphics({
      text: entity.properties.art.getValue(), // 更规范的属性获取方式
      heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, // 核心:让标签相对地面而非贴地
      verticalOffset: new Cesium.Cartesian3(0, 0, 2), // 向上飘2米,数值可按需调
      horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      pixelOffset: new Cesium.Cartesian2(0.0, -40.0),
      depthTestAgainstTerrain: false, // 可选:避免被3D建筑遮挡
    });
  }
});

关键修改说明:

  • heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND:让标签的位置基于贴地的标记点向上计算,不再跟着标记一起贴地
  • verticalOffset: new Cesium.Cartesian3(0, 0, 2):给标签加个垂直偏移,确保它悬浮在地形和建筑上方
  • depthTestAgainstTerrain: false:如果加载了3D建筑,开这个能让标签穿透建筑显示

方法二:手动处理实体位置(进阶场景)

如果你的地形起伏特别大,需要标签始终保持在地面上方固定高度,可以手动计算每个点的地形高度,再给标签设置绝对位置:

promise.then(function (dataSource) {
  viewer.dataSources.add(dataSource);
  const entities = dataSource.entities.values;
  for (const entity of entities) {
    // 手动把实体位置 clamp到地面
    const cartographic = Cesium.Cartographic.fromCartesian(entity.position.getValue());
    const terrainHeight = viewer.scene.globe.getHeight(cartographic) || 0;
    const clampedPosition = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, terrainHeight);
    entity.position = clampedPosition;
    
    // 给标签设置实时更新的位置,确保始终悬浮在地面上方3米
    entity.label = new Cesium.LabelGraphics({
      text: entity.properties.art.getValue(),
      position: new Cesium.CallbackProperty(() => {
        const currentCartographic = Cesium.Cartographic.fromCartesian(entity.position.getValue());
        const currentTerrainHeight = viewer.scene.globe.getHeight(currentCartographic) || 0;
        return Cesium.Cartesian3.fromRadians(currentCartographic.longitude, currentCartographic.latitude, currentTerrainHeight + 3);
      }, false),
      horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      pixelOffset: new Cesium.Cartesian2(0.0, -40.0),
    });
  }
});

这个方案能确保标签在地形变化时也稳稳悬浮,适合山地、丘陵这类复杂地形场景。

内容的提问来源于stack exchange,提问作者minisaurus

火山引擎 最新活动