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

ARKit检测到ARImageAnchor移除聚焦点、未检测到时恢复的实现方法

实现方案

你可以在每帧触发的session(_:didUpdate:)回调中实时检查当前是否存在处于活跃追踪状态的ARImageAnchor,动态控制聚焦点的状态,同时增加防抖逻辑避免频繁切换导致的闪烁问题。

核心注意点

  • 仅判断ARImageAnchor是否存在不准确,需要额外校验isTracked属性为true才代表当前相机正识别到目标图片
  • 增加延迟防抖阈值,避免图片短暂移出视野就触发聚焦点切换

完整修改代码

final class CameraViewController: UIViewController {
  // 改为普通可选型,避免隐式解包风险
  var focusEntity: FocusEntity?
  // 防抖计时器,避免频繁创建/销毁聚焦点
  private var focusRestoreTimer: Timer?
  // 恢复聚焦点的延迟阈值,可根据需求调整,单位为秒
  private let focusRestoreDelay: TimeInterval = 0.5

  override func viewDidLoad() {
        super.viewDidLoad()
        // 其他初始化逻辑...
        // 初始化默认显示聚焦点
        focusEntity = FocusEntity(on: arView, style: .classic(color: .systemGray4))
        arView.session.delegate = self
    }
}

extension CameraViewController: ARSessionDelegate {
    func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        for anchor in anchors {
            if let _ = anchor as? ARImageAnchor {
                // 检测到新的图片锚点,先取消待执行的聚焦点恢复任务
                focusRestoreTimer?.invalidate()
                removeFocusIfNeeded()
            }
        }
    }

    func session(_ session: ARSession, didUpdate frame: ARFrame) {
        // 检查当前是否有处于活跃追踪状态的图片锚点
        let hasActiveImageAnchor = frame.anchors.contains { anchor in
            guard let imageAnchor = anchor as? ARImageAnchor else { return false }
            return imageAnchor.isTracked
        }
        
        if hasActiveImageAnchor {
            // 存在可追踪的图片锚点,移除聚焦点
            focusRestoreTimer?.invalidate()
            removeFocusIfNeeded()
        } else {
            // 无可用图片锚点,延迟恢复聚焦点做防抖处理
            guard focusRestoreTimer == nil, focusEntity == nil else { return }
            focusRestoreTimer = Timer.scheduledTimer(withTimeInterval: focusRestoreDelay, repeats: false) { [weak self] _ in
                guard let self = self else { return }
                // 重新创建并显示聚焦点
                self.focusEntity = FocusEntity(on: self.arView, style: .classic(color: .systemGray4))
                self.focusRestoreTimer = nil
            }
        }
    }
    
    // 抽离移除聚焦点的公共逻辑
    private func removeFocusIfNeeded() {
        guard let focus = focusEntity else { return }
        focus.destroy()
        focusEntity = nil
    }
}

性能优化建议

如果你的FocusEntity支持显隐控制,不需要每次检测到图片就销毁实例,可以通过控制isEnabled或者isHidden属性实现状态切换,避免反复创建实例带来的性能损耗:

// 初始化仅执行一次
override func viewDidLoad() {
    super.viewDidLoad()
    focusEntity = FocusEntity(on: arView, style: .classic(color: .systemGray4))
    // 其他逻辑...
}

// 切换状态的方法修改为
private func setFocusHidden(_ hidden: Bool) {
    focusEntity?.isEnabled = !hidden
    // 若FocusEntity遵循HasVisibility协议也可以用:
    // focusEntity?.isHidden = hidden
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:42:01