hitTest(_:options:) 不识别 ARKit 平面后面的节点

hitTest(_:options:) don't recognize nodes behind ARKit planes

我将一个物体放在墙上,然后尝试识别点击它,但点击测试 returns 0 个物体。当我改变物体的 Z 位置并将其放置在靠近凸轮的位置时,它可以很好地识别,但这不是解决方案,因为平面总是在变化并且它可以随时覆盖物体。如何使 hitTest 正常工作并识别平面后面的节点?或者,也许,我用错了方法?

fileprivate func addNode(atPoint point: CGPoint) {
    let hits = sceneView.hitTest(point, types: .existingPlaneUsingExtent)
    if hits.count > 0, let firstHit = hits.first, let originNode = originNode {
        let node = originNode.clone()
        sceneView.scene.rootNode.addChildNode(node)
        node.position = SCNVector3Make(firstHit.worldTransform.columns.3.x, firstHit.worldTransform.columns.3.y, firstHit.worldTransform.columns.3.z)
        let resize = simd_float4x4(SCNMatrix4MakeScale(0.2, 0.2, 0.2))
        let rotation = simd_float4x4(SCNMatrix4MakeRotation(.pi / 2, -1, 0, 0))
        let transform = simd_mul(firstHit.worldTransform, resize)
        let finalTransform = simd_mul(transform, rotation)
        node.simdTransform = finalTransform
        addedNodes.insert(node)
    }
}

func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else {
        print("Unable to identify touches on any plane. Ignoring interaction...")
        return
    }

    let touchPoint = touch.location(in: sceneView)

    let hits = sceneView.hitTest(touchPoint, options: [SCNHitTestOption.boundingBoxOnly: true])
    let filtered = hits.filter({ addedNodes.contains([=10=].node) })
    print("\(hits.count) vs \(filtered.count), \(hits.first?.node.name ?? "no name")")
    if let node = filtered.first?.node {
        node.removeFromParentNode()
        addedNodes.remove(node)
        return
    }

    addPictureToPlane(atPoint: touchPoint)
}

addedNodes - 设置添加的对象。当我添加平移变换并改变 Z 坐标至少在 0.05(靠近相机)时检测工作正常。至少在平面改变并向前移动节点之前。

我相信你需要做的是改变你的SCNHitTestSearchMode参数,它允许你设置:

Possible values for the searchMode option used with hit-testing methods.

static let searchMode: SCNHitTestOption

据此:

The value for this key is an NSNumber object containing the raw integer value of an SCNHitTestSearchMode constant.

Apple Docs 中,您可以在此处使用三个可能的选项:

case all

The hit test should return all possible results, sorted from nearest to farthest.

case any

The hit test should return only the first object found, regardless of distance.

case closest

The hit test should return only the closes object found.

因此,根据您的问题,您可能需要使用 all case

因此,您的 hitTest function 可能需要看起来像这样(记住 self.augmentedRealityView 指的是 ARSCNView):

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    //1. Get The Current Touch Location
    guard let currentTouchLocation = touches.first?.location(in: self.augmentedRealityView) else { return }

    //2. Perform An SCNHitTest Setting The SearchMode To 1 (All) Which Returns A List Of Results Sorted From Nearest To Farthest
    if #available(iOS 11.0, *) {

        let hitTestResults = self.augmentedRealityView.hitTest(currentTouchLocation, options: [SCNHitTestOption.searchMode: 1])

        //3. Loop Through The Results & Get The Nodes
        for index in 0..<hitTestResults.count{

            let node = hitTestResults[index]
            print(node)

        }
    }
}