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

时间:2018-03-27 07:37:08

标签: swift scenekit arkit

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

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

@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 :)返回检测到的平面。有没有办法只选择我放置的SCNNodes(对象),而不是选择检测到的平面。我错过了什么吗?任何帮助都非常感谢。

谢谢,

Sourabh。

2 个答案:

答案 0 :(得分:1)

要解决此问题,您应该遍历场景节点,之后您可以使用所需的节点进行操作。例如:

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

不要忘记为节点添加名称。例如:

node.name = "yorNodeName"

我希望它有所帮助!

答案 1 :(得分:1)

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

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

(1)ARSCNHitTest

  

在捕获的摄像机图像中搜索与SceneKit视图中的点对应的真实世界对象或AR锚点。

(2)SCNHitTest

  

沿您指定的光线查找SCNGeometry对象。对于光线和几何体之间的每个交点,SceneKit会创建一个命中测试结果,以提供有关包含几何体的SCNNode对象和几何体表面上交点的位置的信息。

因此,以您的UITapGestureRecognizer为例,您可以区分场景中的ARPlaneAnchor(detectPlane)和任何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
    }

}

如果您对name的任何SCNNode使用if let name = nodeTapped.name{ print("An SCNNode Named \(name) Has Been Tapped") } 属性,这也会对您有所帮助,例如:

SCNNodes

此外,如果您只想检测已添加的对象,例如// View(UserControl) side: MVVMContext context = new MVVMContext(); // make sure that the MVVMContext will be destroyed when the UserControl destroyed context.ContainerControl = this; // your View(UserControl) context.SetViewModel(typeof(MyViewModel), viewModel); ,那么您只需删除getureRecognizer函数的第二部分。

希望它有所帮助...