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

Ant*_*RUZ 2 scenekit swift arkit

我将一个对象放在墙上,然后尝试识别点击它,但命中测试返回 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($0.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)
}
Run Code Online (Sandbox Code Playgroud)

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

Bla*_*orz 5

我相信您需要做的是更改SCNHitTestSearchMode允许您设置的参数:

与命中测试方法一起使用的 searchMode 选项的可能值。

static let searchMode: SCNHitTestOption
Run Code Online (Sandbox Code Playgroud)

据此:

这个键的值是一个 NSNumber 对象,它包含一个 SCNHitTestSearchMode 常量的原始整数值。

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

case all
Run Code Online (Sandbox Code Playgroud)

命中测试应该返回所有可能的结果,从最近到最远排序。

case any
Run Code Online (Sandbox Code Playgroud)

命中测试应该只返回找到的第一个对象,而不管距离如何。

case closest
Run Code Online (Sandbox Code Playgroud)

命中测试应该只返回找到的 closes 对象。

因此,根据您的问题,您可能需要使用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)

        }
    }
}
Run Code Online (Sandbox Code Playgroud)