Обнаружение прикосновения к узлу SCNNode в ARKit

Я разместил SCNNode (плоскость) на месте распознанного изображения в бета-версии ARKit 1.5. Я хотел бы вывести сообщение на консоль при нажатии на самолет. Пока у меня есть этот код:

// MARK: - ARSCNViewDelegate (Image detection results)
    /// - Tag: ARImageAnchor-Visualizing
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        guard let imageAnchor = anchor as? ARImageAnchor else { return }
        let referenceImage = imageAnchor.referenceImage
        updateQueue.async {

            // Create a plane to visualize the initial position of the detected image.
            let plane = SCNPlane(width: referenceImage.physicalSize.width,
                                 height: referenceImage.physicalSize.height)
            let planeNode = SCNNode(geometry: plane)
            planeNode.opacity = 0.25

            /*
             `SCNPlane` is vertically oriented in its local coordinate space, but
             `ARImageAnchor` assumes the image is horizontal in its local space, so
             rotate the plane to match.
             */
            planeNode.eulerAngles.x = -.pi / 2

            /*
             Image anchors are not tracked after initial detection, so create an
             animation that limits the duration for which the plane visualization appears.
             */
            //planeNode.runAction(self.imageHighlightAction)

            // Add the plane visualization to the scene.
            node.addChildNode(planeNode)
        }

        DispatchQueue.main.async {
            let imageName = referenceImage.name ?? ""
            self.statusViewController.cancelAllScheduledMessages()
            self.statusViewController.showMessage("Detected image “\(imageName)”")
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first as! UITouch
        if(touch.view == self.sceneView){
            print("touch working")
            let viewTouchLocation:CGPoint = touch.location(in: sceneView)
            guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
                return
            }
            if let planeNode = planeNode, planeNode == result.node {
                print("match")
            }

        }
    }

Но я получаю ошибку «неразрешенный идентификатор» в этой строке: if let planeNode = planeNode, planeNode == result.node {, что я понимаю, потому что planeNode определен в функции Renderer выше и находится не в нужной области. Мой вопрос в том, как это исправить, потому что я не верю, что могу вернуть значение в Renderer, а также не могу поместить функцию touchesBegan в функцию Renderer, чтобы она находилась в нужной области. Может ли кто-нибудь дать мне какие-нибудь идеи, как это исправить? Спасибо!


person ToxicProxy    schedule 18.02.2018    source источник
comment
Чтобы исправить это, вам необходимо понимать разницу между локальными и глобальными переменными: developer.apple.com/library/content/documentation/Swift/, который не имеет отношения к Scenekit или ARkit, но имеет очень простое программирование. Или попробуйте этот: youtube.com/watch?v=qRZAdbAgj3c   -  person Xartec    schedule 19.02.2018
comment
Разобрался благодаря этому. Ты лучший!   -  person ToxicProxy    schedule 21.02.2018


Ответы (2)


Чтобы решить эту проблему, объявите глобальную переменную в вашем ViewController.

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    var planeNode : SCNNode? = nil

    .....

}

Затем используйте только что объявленную переменную planeNode и назначьте ее своему фактическому planeNode в методе рендеринга.

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {

     .........

     let planeNode = SCNNode(geometry: plane)
     self.planeNode = planeNode
}

Таким образом, вы можете получить доступ к planeNode из любого места внутри класса.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first as! UITouch
    if(touch.view == self.sceneView){
        print("touch working")
        let viewTouchLocation:CGPoint = touch.location(in: sceneView)
        guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
            return
        }
        if let planeNode = planeNode, planeNode == result.node {
            print("match")
        }

    }
}
person fannolo    schedule 18.08.2018
comment
Эй, как добавить новый scnnode, когда пользователь касается плоскости? - person PvDev; 30.08.2018

// Add a gesture recognizer
 let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    self.sceneView.addGestureRecognizer(tapGestureRecognizer)
    tapGestureRecognizer.cancelsTouchesInView = false 

@objc func handleTap (отправитель: UITapGestureRecognizer) {

    guard let sceneView = sender.view as? ARSCNView else {return}
    let touchLcoation = sender.location(in: sceneView)
    let hitTestResult = sceneView.hitTest(touchLcoation, types: .existingPlaneUsingExtent)

    if !hitTestResult.isEmpty {
        // add something to scene 
        // e.g self.sceneView.scene.rootNode.addChildNode(yourNode!)
    }
}
person ovidiur    schedule 25.09.2018