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

如何检测ARReferenceImage已不在相机视野中?含遮挡与移除场景

解决ARReferenceImage离开视野/被遮挡时的状态判断问题

这个问题我之前也碰到过——单纯靠节点的可见性判断确实不靠谱,因为ARKit在图像丢失后会保持节点的位置,导致即使图像不在视野里,节点依然会被判定在视锥体范围内。下面给你两个核心的改进思路,结合起来就能准确判断图像是否真的处于相机视野中:

1. 依赖ARKit的图像追踪状态(最核心的判断)

ARKit的ARImageAnchor自带一个isTracked属性,这个属性才是判断图像是否被相机实际追踪到的关键:

  • 当图像在相机视野内、能被稳定识别时,isTracked为true
  • 当图像被移出视野、被遮挡到无法识别,或者光照/角度变化导致追踪丢失时,isTracked会变为false

代码改造步骤:

首先,先存储当前追踪的图像锚点和对应节点:

var currentImageAnchor: ARImageAnchor?
var currentImageNode: SCNNode?

然后在锚点添加时记录目标锚点和节点:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    // 替换成你的目标图像名称
    if imageAnchor.referenceImage.name == "TargetImage" {
        currentImageNode = node
        currentImageAnchor = imageAnchor
    }
}

别忘了在锚点更新时同步状态:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor, imageAnchor == currentImageAnchor else { return }
    currentImageAnchor = imageAnchor
}

2. 可选:添加遮挡检测(区分“被遮挡”和“移出视野”)

如果需要更精准的判断——比如图像还在视野里,但被其他3D物体遮挡住了——可以用场景的射线检测来判断:

修改你的updateAtTime方法:

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 
    guard let node = currentImageNode, let anchor = currentImageAnchor else { return } 

    // 核心:检查ARKit是否还在追踪图像
    let isTracked = anchor.isTracked
    
    // 可选:检测图像是否被其他节点遮挡
    var isOccluded = false
    if let pointOfView = sceneView.pointOfView {
        // 从相机位置向图像节点中心发射射线
        let cameraPosition = pointOfView.position
        let imagePosition = node.position
        let direction = imagePosition - cameraPosition
        
        // 执行射线检测,忽略隐藏节点
        let hitResults = sceneView.hitTest(
            cameraPosition,
            direction: direction,
            options: [
                SCNHitTestOption.searchMode: SCNHitTestSearchMode.all.rawValue,
                SCNHitTestOption.ignoreHiddenNodes: true
            ]
        )
        
        // 如果第一个命中的节点不是目标图像节点,说明被遮挡
        if let firstHit = hitResults.first, firstHit.node != node {
            isOccluded = true
        }
    }
    
    // 最终判断:未追踪 或 被遮挡 = 图像不在有效视野中
    let isImageNotInView = !isTracked || isOccluded
    
    if isImageNotInView {
        // 执行图像不在视野的逻辑,比如隐藏节点、触发回调
        node.isHidden = true
        print("图像已离开视野或被遮挡")
    } else {
        node.isHidden = false
        print("图像在视野中且可追踪")
    }
}

关键说明:

  • 优先用anchor.isTracked:这是ARKit底层通过图像识别算法给出的最可靠状态,比单纯的节点位置判断准确得多
  • 遮挡检测是补充:如果你的场景里没有其他3D物体遮挡图像,只靠isTracked就足够解决问题
  • 注意清理状态:当切换场景或停止追踪时,记得把currentImageAnchor和currentImageNode置为nil

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:23:34