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

如何在SceneView中对节点子节点做HitTest?ARSceneView点击检测异常

解决ARSceneView图像识别后点击被隐形平面干扰的问题

老哥,我太懂你这个糟心的问题了!之前做AR图像识别项目时也踩过一模一样的坑——ARKit在检测到图像锚点后,有时候会偷偷生成一个隐形的平面锚点,刚好盖在你手动添加的子节点上面,导致TapGestureRecognizer优先命中这个平面,根本碰不到你想要的目标节点。下面给你几个亲测有效的解决思路:

1. 直接关闭自动平面检测(最省心的方案)

如果你的场景只需要图像识别,不需要平面检测功能,那直接在AR配置里关掉平面检测选项,从根源上杜绝这个隐形平面的生成:

let configuration = ARWorldTrackingConfiguration()
// 加载你的识别图像集
configuration.detectionImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil)
// 关键:禁用自动平面检测,避免生成多余的平面锚点
configuration.planeDetection = []
sceneView.session.run(configuration)

2. 过滤点击结果,只识别自定义节点

如果必须保留平面检测功能,那就在处理点击手势时,精准过滤出你自己添加的节点,排除平面节点:

@objc func handleTap(_ gesture: UITapGestureRecognizer) {
    let tapLocation = gesture.location(in: sceneView)
    
    // 用精确的节点检测,只命中可见的、非平面的自定义节点
    let preciseHitResults = sceneView.hitTest(tapLocation, options: [
        SCNHitTestOption.ignoreHiddenNodes: true,
        SCNHitTestOption.boundingBoxOnly: true
    ])
    
    // 优先处理我们的目标节点
    if let hitResult = preciseHitResults.first {
        // 可以给自定义节点加个标记(比如类名、name属性)来判断
        if hitResult.node.name == "MyCustomTargetNode" {
            print("终于点到目标节点啦!")
            // 这里写你的点击逻辑
            return
        }
    }
    
    // 如果需要处理平面点击,再走下面的逻辑(可选)
    // ...
}

3. 调整节点层级,让自定义节点“浮”在平面上面

通过修改节点的zPosition或者renderingOrder,让你的子节点在渲染和交互优先级上高于平面节点:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    
    // 创建你的自定义节点
    let targetNode = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0))
    targetNode.name = "MyCustomTargetNode"
    
    // 关键:把节点往镜头方向挪一点(z轴值越小越靠前),避开平面的遮挡
    targetNode.simdPosition.z -= 0.01
    // 或者设置渲染顺序,值越大越晚渲染(也就是显示在最上层)
    targetNode.renderingOrder = 10
    
    node.addChildNode(targetNode)
}

4. 手动禁用平面节点的交互或隐藏它

如果能捕捉到自动生成的平面锚点,可以直接禁用它的交互能力或者隐藏:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    // 识别到平面锚点时,禁用它的交互并隐藏
    if anchor is ARPlaneAnchor {
        node.isUserInteractionEnabled = false
        node.isHidden = true
        // 顺便把平面的网格子节点也处理了
        for childNode in node.children {
            childNode.isHidden = true
            childNode.isUserInteractionEnabled = false
        }
    } else if let imageAnchor = anchor as? ARImageAnchor {
        // 添加自定义节点的逻辑
    }
}

这些方案里,优先推荐第一种(关闭平面检测),最直接高效;如果场景必须用到平面检测,第二种和第三种组合起来用效果最好。

内容的提问来源于stack exchange,提问作者Vasilis D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:46:49