如何检测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
相关产品推荐
相关产品推荐

