首页 文章

检测 ARKit 中的 SCNNode 上的触摸

提问于
浏览
1

我已将一个 SCNNode(一个平面)放置在 ARKit 1.5 beta 中识别图像的位置。我想在点击飞机时向控制台打印一条消息。到目前为止,我有这个代码:

// 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 函数中,因此它在正确的范围内。谁能给我任何关于如何解决这个问题的想法?谢谢!

2 回答

  • 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")
            }
    
        }
    }
    
  • 0
    // Add a gesture recognizer
     let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        self.sceneView.addGestureRecognizer(tapGestureRecognizer)
        tapGestureRecognizer.cancelsTouchesInView = false
    

    _1_func handleTap(sender: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!)
        }
    }
    

相关问题