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
相关产品推荐
相关产品推荐

