ARCore 中文文档 下载 App

地形高程与海拔精度控制

为什么"高度"总是不准

在 AR 应用中,高度相关的问题频繁出现:

这些问题的核心是:地球没有一个"标准高度"。不同参考系下的"海拔"是不一样的。

四种高度参考系

参考系定义与 WGS84 的差异
WGS84 椭球一个数学上定义的理想椭球面官方 GPS 用这个,和真实地面差 0~50 米
大地水准面(Geoid)假想的"平均海平面"——全球重力等位面比 WGS84 椭球更接近真实地面,但仍有局部差异
地形表面(Terrain)该经纬度位置实际的地面高度谷歌 Elevation API 提供的就是这个
建筑屋顶(Rooftop)建筑物最高点的高度Google 街景 LiDAR + 建筑模型

Terrain Anchor 用的是第三种——地形表面高度。这是最接近开发者直觉的:"我想把东西放在地面以上 1.5 米"。

Terrain Anchor 的高程数据来源

Google 从多个来源拼接出全球地形高度数据:

来源覆盖精度分辨率
SRTM(Shuttle Radar Topography Mission)全球陆地10~15 米30~90 米网格
ALOS World 3D全球~5 米12 米网格
街景 LiDAR街道路面和建筑亚米级点云级别
Google Earth Engine持续更新的卫星数据因地区而异10~30 米

把这些数据融合在一起,ARCore 的 Terrain Anchor 在大多数城市区域的地面高程精度在 1~5 米之间。

高程不准的常见原因

情况一:建筑密集区

街道两侧高楼林立时,Terrain 数据可能把"街道地面"和"屋顶"的高程搞混——Google 需要正确识别地形特征。高密度城市区域(比如香港、东京)精度可能下降。

情况二:山区/丘陵

SRTM 数据在陡峭山区的精度显著下降——分辨率只有 30 米网格,陡坡上的一个点和附近网格点的高程可能差十几米。

情况三:人工结构

桥梁、水坝、人工台地等结构的高度不在任何标准地形数据集里。Google 会用街景 LiDAR 补,但不是所有人工结构都覆盖。

情况四:海平面高度差

某些地区(尤其是岛屿或新填海区域)的地形高程本身就不准确——SRTM 是航天飞机测的,当时海平面和现在不同。

校正策略

策略一:VPS 定位时让手机靠近目标高度

VPS 定位不仅返回水平位置,也返回设备的当前高度。如果你的 AR 内容是给"站在地面上的人"看的,可以:

// 用户打开应用,让手机与地面平齐
val initialPose = arSession.earthCameraPose
val userGroundAltitude = initialPose.altitude  // 手机的 VPS 精确高度

// 用这个高度作为参考,计算 Terrain Anchor 的 altitudeAboveTerrain
val targetLat = 37.7749
val targetLng = -122.4194
val terrainAnchorAltitude = 0.0  // 先假设刚好在地面

// 创建 Anchor 后,观察实际渲染效果,可能需要 +2m 或 -3m 校正
// 把校正值做成可调参数让用户微调

策略二:给用户一个高度微调 UI

AR 内容放好后,让用户可以上下滑动调整高度(±5 米范围)。把校正值存到本地,下次自动使用。

策略三:结合 SLAM 地面检测

VPS 定位到大致位置后,ARCore 的本地 SLAM 会检测附近的几何平面。可以用这些平面的 Y 坐标来校正 Terrain Anchor 的高度:

val terrainAnchorPose = terrainAnchor.pose  // VPS 给出的位置

// SLAM 检测到地面平面
val groundPlane = session.getAllTrackables<Plane>()
    .firstOrNull { it.type == Plane.Type.HORIZONTAL_UPWARD_FACING }

if (groundPlane != null) {
    val slamGroundY = groundPlane.centerPose.translation.y
    val terrainAnchorY = terrainAnchorPose.translation.y

    // 用 SLAM 地面高度校正 Terrain Anchor 的 Y
    val correction = slamGroundY - terrainAnchorY
    terrainAnchor.pose = terrainAnchorPose.compose(
        Pose.makeTranslation(0f, correction, 0f)
    )
}

这种方法在 VPS 精度好的区域(亚米级)基本不需要,在精度差的区域效果明显。

策略四:用 Rooftop Anchor 处理特殊结构

如果你的 AR 内容是放在屋顶上的,直接用 Rooftop Anchor 而不是 Terrain Anchor——Google 会自动减去屋顶高程。

调试高程的实用技巧

在开发中怎么验证高度对不对

  1. 找地标参考:在一个有已知高度地标(如雕像、纪念碑)的位置测试,对比 AR 内容和地标的实际高度
  2. 多人比对:让多台设备在同一位置打开应用,观察 AR 内容高度是否一致
  3. 可视化高度差:调试时给 AR 内容加一个垂直方向的标尺,直观显示"距离地面还有多远"

Unity 中的高度调试

void Update()
{
    var geospatialPose = session.GetComponent<ARCameraManager>()
        .GetGeospatialPose();

    // 实时在屏幕上显示当前高度
    Debug.Log($"当前高度: {geospatialPose.altitude:F2}m, " +
              $"精度: {geospatialPose.altitudeAccuracy:F2}m");
}

与 Depth API 的配合

在 Terrain Anchor 位置启用本地 Depth API(如果设备支持),Depth API 的逐像素深度数据可以用来做近距离的高度校正——VPS 给的是大尺度定位,Depth API 给的是厘米级的局部表面细节。两者结合能实现: