ARCore 中文文档 下载 App

跟踪丢失漂移和恢复策略

问题表现

用户打开 AR 应用后,虚拟物体:

这些统称为跟踪质量问题。

跟踪丢失的三种阶段

ARCore 用 TrackingState 表示跟踪质量:

状态含义用户能看到的现象
TRACKING正常虚拟物体稳定不动
PAUSED暂时丢失,正在恢复虚拟物体可能轻微漂移或短暂闪烁
STOPPED彻底丢失,需要重新初始化虚拟物体消失(或一直飘着),AR 功能不可用

各阶段处理策略

// 在每一帧检查所有 Trackable 的状态
fun updateTrackingState() {
    session.getAllTrackables<Any>().forEach { trackable ->
        when (trackable.trackingState) {
            TrackingState.TRACKING -> {
                // 正常,继续渲染虚拟物体
            }
            TrackingState.PAUSED -> {
                // 暂时丢失:淡化虚拟物体 + 给用户提示
                virtualObject.alpha = 0.5f
                showTrackingTip("请缓慢移动手机让我重新识别环境")
            }
            TrackingState.STOPPED -> {
                // 彻底丢失:隐藏虚拟物体 + 引导用户重新开始
                virtualObject.alpha = 0f
                showRestartTip("跟踪丢失,请重新扫描环境开始")
            }
        }
    }
}

为什么会丢失跟踪

原因一:环境没有足够特征点

纯白墙面 ← 没有特征点 → SLAM 无法构建地图 → 丢失
光滑桌面 ← 特征点少 → 跟踪不稳定
漆黑房间 ← 摄像头无有效数据 → 立刻丢失

解决:引导用户走到特征点丰富的地方("请把手机对准有图案的地面、有纹理的墙壁、或带家具的区域")。

原因二:快速运动

用户快速挥舞手机 → 画面模糊 → 特征点无法跨帧匹配 → 丢失

解决:引导用户缓慢移动——"请慢慢移动手机来扫描周围环境"。

原因三:走出了扫描区域

用户一直把手机对准同一个角落 → SLAM 地图只构建了这一小块 → 
用户走出这个区域时 SLAM 对新区域完全未知 → 丢失

解决:引导用户先扫描整个房间——"请先缓慢移动手机扫过整个房间"。这是 AR 应用最经典的引导文案。

原因四:光照条件突变

用户从明亮房间走到暗走廊 → 摄像头突然曝光不足 → SLAM 失准
闪光灯突然打开 → 摄像头过曝 → SLAM 失准

解决:检测到 TrackingState 变化时给用户提示,让他们适应新光照条件。

原因五:动态物体太多

画面中充满走动的人、跑动的狗、行驶的车辆 → 
ARCore 的静态世界假设被破坏 → 特征点被动态物体干扰 → 失准

解决:提示用户"AR 效果在静态环境中最好",或让用户避开人群。

累积漂移:怎么办

累积漂移(Accumulated Drift)是指长时间使用后虚拟物体慢慢"飘"了——这不是跟踪丢失,而是 SLAM 在纯本地模式下无法修正全局误差。

普通 SLAM 的累积漂移

纯本地 SLAM 存在经典问题:没有回环(Loop Closure)时,累积误差只会增大。如果用户只在一个有限区域内走动,SLAM 会不断迭代求精;但如果用户走了一圈回到起点,没有回环检测就会产生几米的误差。

解决累积漂移的手段

手段原理效果
回环检测当 SLAM 检测到回到已知位置时修正全局地图自动,对用户透明
Cloud Anchors解析 Cloud Anchor 时强制对齐到云端地图需网络,精度最高
Geospatial API + VPSVPS 定期重新定位纠正 SLAM 误差需网络,持续对齐
定期重置引导用户每隔几分钟重新扫描打扰用户,但有效
选择锚点策略用 Trackable Anchor(跟随平面)而不是世界坐标 Anchor基础缓解

Geospatial 定期重定位

// 每 30 秒检查一下 Geospatial 定位精度
private var lastVPSCheck = 0L
private val vpsCheckInterval = 30_000L  // 30 秒

fun checkVPSRelocalization() {
    val now = System.currentTimeMillis()
    if (now - lastVPSCheck < vpsCheckInterval) return
    lastVPSCheck = now

    if (!session.isGeospatialModeSupported(GeospatialMode.ENABLED)) return

    val earthPose = earth.cameraGeospatialPose
    if (earthPose.altitudeAccuracy > 5f || earthPose.headingAccuracy > Math.toRadians(20.0)) {
        // VPS 精度不够,提示用户
        showVPSWarning("位置精度下降,建议到视野开阔处使用")
    } else if (earthPose.altitudeAccuracy < 1f) {
        // VPS 精度很好,可以考虑用它重新对齐本地坐标
        // 这需要重新解析 Geospatial Anchor
    }
}

恢复流程设计

一个完整的恢复流程应该是自动检测 → 友好提示 → 引导恢复:

// 1. 监听 TrackingState 变化
// 2. PAUSED 时:淡化虚拟物体 + 显示"请缓慢移动"
// 3. STOPPED 时:隐藏所有 AR 内容 + 显示完整引导界面
// 4. 恢复后:渐变显示虚拟物体 + 不打扰用户

fun onTrackingStateChanged(newState: TrackingState) {
    when (newState) {
        TrackingState.TRACKING -> {
            fadeInVirtualContent()  // 恢复显示
            if (wasPausedOrStopped) {
                showRecoveryToast("跟踪已恢复")  // 可选的成功提示
            }
        }
        TrackingState.PAUSED -> {
            fadeOutVirtualContent(0.5f)
            showMinimalGuide("缓慢移动手机以恢复")
        }
        TrackingState.STOPPED -> {
            hideAllVirtualContent()
            showFullRecoveryUI(
                title = "跟踪丢失",
                tip = "请缓慢移动手机,扫过周围的环境(地面、墙壁、家具)以重新识别"
            )
        }
    }
}

Unity 中的跟踪恢复

using UnityEngine.XR.ARFoundation;

public class TrackingRecovery : MonoBehaviour
{
    private ARSession session;

    void Start()
    {
        session = GetComponent<ARSession>();
        session.trackingStateChanged += OnTrackingStateChanged;
    }

    void OnTrackingStateChanged(ARTrackingState state)
    {
        switch (state)
        {
            case ARTrackingState.Tracking:
                // 正常
                break;
            case ARTrackingState.NotTracking:
                // 丢失
                StartCoroutine(RecoverTracking());
                break;
        }
    }

    IEnumerator RecoverTracking()
    {
        // 自动重置 Session 让 SLAM 重新初始化
        session.Reset();
        // 给用户看引导 UI
        recoveryUI.Show();
        // 等待用户移动 + SLAM 重新跟踪
        yield return new WaitUntil(() => session.trackingState == ARTrackingState.Tracking);
        recoveryUI.Hide();
    }
}

防丢失的主动策略

除了被动检测和恢复,还可以主动降低丢失概率:

策略说明
首次打开自动扫描引导不要让用户直接进 AR 场景,先引导"扫一下房间"
实时反馈跟踪质量在 AR 画面角落显示一个小指示器:绿=好、黄=警告、红=丢
光照变化检测亮度突然降低很多时主动提示"光线变暗了,AR 效果可能受影响"
移动速度检测IMU 检测到设备快速移动时提示"请放慢一些"