无法区分 ARKit 检测到的平面和使用 HitTest 放置的数字对象

Unable to differentiate between plane detected by ARKit and a digital object to be placed using HitTest

我对 iOS Swift 编程还很陌生。我正在使用 ARKit 构建一个非常基本的应用程序来检测水平面并在其上放置、平移、旋转、修改或删除对象。

我主要关心的是 ARKit 检测到的平面与我放置的数字对象之间的差异。我的想法是使用 hitTest(:options:) 到 select 对象(如果有的话)和 hitTest(:types:) 到 select 飞机通过点击手势。我在下面附上了相关的代码片段。

@objc func tapped(_ gesture: UITapGestureRecognizer){

    let sceneView = gesture.view as! ARSCNView

    let location = gesture.location(in: sceneView)


    let hitTestOptions: [SCNHitTestOption: Any] = [.boundingBoxOnly: true]
    let existingNodeHitTest = sceneView.hitTest(location, options: hitTestOptions)

    if let existingNode = existingNodeHitTest.first?.node {

        // Move, rotate, modify or delete the object

    } else {

        // Option to add other objects

        let hitTest = sceneView.hitTest(location, types: .existingPlaneUsingExtent)

        if !hitTest.isEmpty {

            let node = findNode(at: location)

            if node !== selectedNode {

                self.addItems(hitTestResult: hitTest.first!)


            } 

        }

}

}

func addItems(hitTestResult: ARHitTestResult) {


        let scene = SCNScene(named: "BuildingModels.scnassets/model/model.scn")


        let itemNode = (scene?.rootNode.childNode(withName: "SketchUp", recursively: false))!


        let transform = hitTestResult.worldTransform
        let position = SCNVector3(transform.columns.3.x,transform.columns.3.y,transform.columns.3.z)
        itemNode.position = position
        //            self.sceneView.scene.lightingEnvironment.contents = scene.lightingEnvironment.contents

        self.sceneView.scene.rootNode.addChildNode(itemNode)
        selectedNode = itemNode

}

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor else {return}

    let gridNode = createGrid(planeAnchor: planeAnchor)
    node.addChildNode(gridNode)


}

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor else {return}

    node.enumerateChildNodes { (childNode, _) in
        childNode.removeFromParentNode()
    }

    let gridNode = createGrid(planeAnchor: planeAnchor)
    node.addChildNode(gridNode)

}

当我 运行 代码时, hitTest(_:options:) returns 检测到飞机。有什么方法可以 select 只有我放置的 SCNNodes(对象)而不是检测到的平面。我错过了什么吗?非常感谢任何帮助。

谢谢,

Sourabh.

要解决此问题,您应该循环遍历场景节点,然后您可以使用您想要的节点进行操作。示例:

    for node in sceneView.scene.rootNode.childNodes {
            if node.name == "yorNodeName" {
               // do your manipulations
            }
        }

不要忘记为您的节点添加名称。示例:

node.name = "yorNodeName"

希望对您有所帮助!

看看你的问题,你已经完成了一半。

完整处理此问题的方法是在 UITapGestureRecognizer 函数中使用以下 HitTest 函数:

(1) 一个 ARSCNHitTest 其中:

Searches for real-world objects or AR anchors in the captured camera image corresponding to a point in the SceneKit view.

(2) 一个SCNHitTest 其中:

Looks for SCNGeometry objects along the ray you specify. For each intersection between the ray and and a geometry, SceneKit creates a hit-test result to provide information about both the SCNNode object containing the geometry and the location of the intersection on the geometry’s surface.

因此,以您的 UITapGestureRecognizer 为例,您可以像这样区分场景中的 ARPlaneAnchor(检测到的平面)和任何 SCNNode

@objc func handleTap(_ gesture: UITapGestureRecognizer){

    //1. Get The Current Touch Location
    let currentTouchLocation = gesture.location(in: self.augmentedRealityView)

    //2. Perform An ARNSCNHitTest To See If We Have Hit An ARPlaneAnchor
    if let planeHitTest = augmentedRealityView.hitTest(currentTouchLocation, types: .existingPlane).first,
        let planeAnchor = planeHitTest.anchor as? ARPlaneAnchor{

        print("User Has Tapped On An Existing Plane = \(planeAnchor.identifier)")
        return
    }

    //3. Perform An SCNHitTest To See If We Have Hit An SCNNode
    if let nodeHitTest = augmentedRealityView.hitTest(currentTouchLocation, options: nil).first {

        let nodeTapped = nodeHitTest.node

        print("An SCNNode Has Been Tapped = \(nodeTapped)")
        return
    }

}

如果您对任何 SCNNode 使用 name 属性,这也将进一步帮助您,例如:

if let name = nodeTapped.name{
    print("An SCNNode Named \(name) Has Been Tapped")
}

此外,如果您只想检测已添加的对象,例如 SCNNodes,那么您只需删除 getureRecognizer 函数的第二部分即可。

希望对您有所帮助...