Cesium 中 disableDepthTestDistance 与 distanceDisplayCondition 的区别:铁路分段图层标签管理实战

Cesium 的 disableDepthTestDistance 和 distanceDisplayCondition 虽然都控制物体的可见性,但前者决定标签是否被地形或模型遮挡,后者决定物体在哪个距离范围内显示。本文结合铁路设计系统的分段图层加载场景,详细拆解两者的区别、适用场景和搭配技巧。

为什么会搞混这两个参数

在 Cesium 里做三维 GIS 开发的人,几乎都遇到过同一个困惑:disableDepthTestDistancedistanceDisplayCondition,名字里都带着距离相关的字眼,看起来都影响物体怎么显示,到底有什么区别?

如果你也在做铁路设计系统,正在加载分段图层,会发现沿着铁路线密密麻麻的 label 糊在一起,根本看不清。你可能会想:让远处的 label 藏起来,或者让 label 不被地形挡住。这时候两个参数都会出现在你的搜索框里。

但把它们搞清楚之前,一个参数调不好,另一个又调过头,画面反而更乱。

disableDepthTestDistance:决定 label 能不能穿墙

先说本质:这个参数控制的是 深度测试(depth test) 的行为。Cesium 默认会对所有物体做深度测试——一个 label 如果被地形、建筑或其他模型挡住,就不会绘制。这很符合物理世界,但有时你希望 label 始终显示在最前面。

disableDepthTestDistance 的完整行为是:在相机距离物体 小于等于 这个值的范围内,关闭深度测试。也就是说,这个 label 不会被任何东西遮挡,始终浮在最上面。一旦相机距离 超过 这个值,深度测试恢复,label 开始受遮挡影响。

// 示例:相机在物体距离 1000 米内时,label 始终可见,不被地形遮挡
label.disableDepthTestDistance = 1000.0;

设为 0.0 表示不关闭深度测试(默认行为)。设为 Infinity 表示永远关闭深度测试,label 永远不被遮挡。

你可能会下意识把它理解成”可见距离”,但这个理解是错的。它只管是否遮挡,不管显示多远

distanceDisplayCondition:决定 label 在多远范围内出现

这个就直观多了。distanceDisplayCondition 是一个 NearFar 结构(本质是一个二维向量),定义了物体可见的相机距离范围。

// 示例:相机距离在 200 米到 5000 米之间时显示 label
label.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(200.0, 5000.0);
  • near:相机小于这个距离时,物体隐藏(太近了不显示)
  • far:相机大于这个距离时,物体隐藏(太远了不显示)

这个才是真正的”可见距离”。它决定了物体在什么距离范围内出现,跟遮挡没有任何关系。

两者的本质区别

disableDepthTestDistance:控制是否做深度测试(遮挡)。核心逻辑是近处不遮挡,远处恢复遮挡。典型用途是让 label 不被地形/建筑挡住。默认值 0.0(不做特殊处理)。

distanceDisplayCondition:控制可见的距离范围。核心逻辑是近处隐藏,远处隐藏,中间可见。典型用途是让远处密集 label 自动消失。默认值 undefined(始终可见)。

可以这样记:前者是穿透能力,后者是有效射程

铁路设计系统中的实战场景

回到你的铁路分段图层加载场景。假设你有几百公里的铁路线,划分成若干分段,每个分段有一个 label 显示桩号、分段名称和状态。

问题 1:远处 label 拥挤

相机拉远后,几百个 label 全部显示,密密麻麻堆在一起,UI 完全没法看。

解决方案是用 distanceDisplayCondition层级疏密控制

// 主要分段:500 米外开始显示,8000 米之外隐藏
mainLabel.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(500.0, 8000.0);

// 次要分段:只在 2000 米内显示
minorLabel.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(500.0, 2000.0);

这样近景时细节丰富,拉远后只保留主要信息,自动降噪。

问题 2:label 被地形吃掉

铁路线经常穿过山谷、隧道、桥梁区域。label 在起伏地形中很容易被遮挡。用 disableDepthTestDistance 解决:

// 相机 3000 米内,label 始终在最上层
label.disableDepthTestDistance = 3000.0;

注意别设成 Infinity,否则超远距离的 label 也会浮在画面最前面,遮挡视线,破坏沉浸感。

问题 3:两者一起用

这是最常见也最合理的方式:

const label = viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(lng, lat, height),
  label: {
    text: `DK${mileage}+${offset}`,
    font: '14px sans-serif',
    fillColor: Cesium.Color.WHITE,
    outlineColor: Cesium.Color.BLACK,
    outlineWidth: 2,
    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
    // 500 米内不显示(太近了不需要看标签),5000 米外隐藏
    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(500.0, 5000.0),
    // 3000 米内不被遮挡
    disableDepthTestDistance: 3000.0,
  }
});

这样就实现了:label 只在 500~5000 米的距离范围内显示,并且 3000 米内始终不被地形遮挡。远场景下 label 自动消失,近场景下清晰可读。

容易踩坑的地方

坑 1:disableDepthTestDistance 不是可见距离

这是最常见的误解。把 disableDepthTestDistance 设成 1000,不会让 1000 米外的 label 消失。它只控制 1000 米内是否做深度测试。想让 label 消失,用 distanceDisplayCondition。两个概念完全不重叠。

坑 2:disableDepthTestDistance 设为 Infinity 的副作用

如果你的 label 很多,又全部设为 Infinity,意味着所有 label 永远不做深度测试。它们会叠加在其他 3D 物体之上,包括其他 label 之间也会相互覆盖,造成视觉混乱。GPU 的深度缓冲区利用率也会下降,极端情况下影响性能。尽量给一个合理值,比如最大分段长度的 1.5 倍。

坑 3:distanceDisplayCondition 配合 label 的 heightReference

如果 label 使用了 CLAMP_TO_GROUND,label 会贴在地面上,可能导致近处距离条件难以触发。建议分段 label 使用绝对高度或 RELATIVE_TO_GROUND 来稳定距离行为。

坑 4:更新动态分段时忘记重置参数

铁路分段可能根据设计变更动态合并或拆分。如果复用一个 Entity 对象,记得在更新 label 属性时同时更新两个参数,否则旧参数会残留:

function updateSegmentLabel(entity, config) {
  entity.label.distanceDisplayCondition =
    new Cesium.DistanceDisplayCondition(config.near, config.far);
  entity.label.disableDepthTestDistance = config.depthTestDistance;
}

发布后的检查清单

  • 拉远视角确认 label 数量是否按预期减少
  • 切换到山谷视角,确认 label 没有被地形吃掉
  • 旋转视角时 label 是否漂移或闪烁
  • 切换不同分段加载策略,参数是否自动更新
  • 在不同缩放级别截图对比,验证疏密效果
  • 记录每个分段使用的距离参数,方便上线后调优

总结

disableDepthTestDistancedistanceDisplayCondition 是 Cesium 中容易混淆但用途完全不同的两个参数。前者控制遮挡与否,后者控制显示范围。在铁路分段图层加载的场景中,合理搭配两者可以优雅地解决 label 拥挤和被遮挡两大痛点。

我的建议是:永远从 distanceDisplayCondition 想起,先把可见距离范围定好,再看是否需要 disableDepthTestDistance 解决遮挡问题。顺序反过来,大概率会调出奇怪的效果。

分段图层本身就是一种信息降维的设计——把大量数据按空间或语义拆分成有序的块。Label 的距离控制可以看作这种设计在视觉层面的延伸:近处给细节,远处给结构,用户才能在三维场景里快速理解路网整体与局部的关系。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注