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

