【问题标题】:detect which plane is tapped on arkit检测在 arkit 上轻敲哪架飞机
【发布时间】:2018-02-20 23:25:21
【问题描述】:

我正在使用 ARKit,并且我在一个场景中有多个平面节点 (SCNPlanes)。我想使用 hittest 来检测飞机上的触摸,但我不确定如何检测哪个飞机被轻敲。从我的图像识别代码中,每架飞机都有一个与之关联的名称。这是我的 TouchesBegan 函数:

//detects taps on transparent planes created by reference images
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first as! UITouch
        if(touch.view == self.sceneView){
            let viewTouchLocation:CGPoint = touch.location(in: sceneView)
            guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
                return
            }
            print("results", "\(result)")
            let touchPlaneNode = planeNode
            if touchPlaneNode == result.node {
                print("tapped on a match, but which plane did I tap on?")
            }

        }
    }

谢谢!

【问题讨论】:

    标签: ios scenekit arkit


    【解决方案1】:

    假设我已正确阅读您的问题,一个好的开始方法是将 ARPlaneAnchor 及其关联的 SCNNode 存储在字典中,例如:

        var planes = [ARPlaneAnchor: PlaneNode]()
    

    在我的例子中,'Plane Node' 值是一个自定义 SCNNode,但你可以存储任何你喜欢的节点。

    然后将在以下 ARSCNView 委托方法中创建此引用:

     func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    
            //1. Check The We Have An ARPlane Anchor
            guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
    
            //2. Create Our Plane Node
            let planeNode = PlaneNode(anchor: planeAnchor, node: node, image: true, identifier: planes.keys.count, opacity: 1)
    
            //3. Store A Reference To It
            planes[planeAnchor] = planeNode
    
    
    }
    

    然后在 Touches Began 中,您可以执行以下操作:

       override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
        /*
         1. Get The Current Touch Location
         2. Check That We Have Touched A Valid Node
         3. Check That Our Touched Object Is An ARPlane Anchor
         4. Determine If It Is One That Has Been Stored
         5. Get It's Name
         */
    
        guard let touchLocation = touches.first?.location(in: augmentedRealityView),
            let hitTest = augmentedRealityView.hitTest(touchLocation, types: .existingPlaneUsingExtent).first,
            let planeAnchor = hitTest.anchor as? ARPlaneAnchor,
            let detectedPlane = self.planes[planeAnchor],
            let nodeID = detectedPlane.name
            else {
                 //No Valid Plane Has Been Detected
                return
    
        }
    
        print(nodeID)
    
    
    }
    

    在 touchesBegan 方法中,augmentedRealityView 指的是设置为 IBOutlet 的 ARSCNView。

    我的 PlaneNode 类看起来像这样(您需要添加自己的图像,在我的 Assets Bundle 中称为:defaultGrid):

    class PlaneNode: SCNNode {
    
    let DEFAULT_IMAGE: String = "defaultGrid"
    let NAME: String = "PlaneNode"
    var planeGeometry: SCNPlane
    var planeAnchor: ARPlaneAnchor
    
    var widthInfo: String!
    var heightInfo: String!
    var alignmentInfo: String!
    
    //---------------
    //MARK: LifeCycle
    //---------------
    
    /// Inititialization
    ///
    /// - Parameters:
    ///   - anchor: ARPlaneAnchor
    ///   - node: SCNNode
    ///   - node: Bool
    init(anchor: ARPlaneAnchor, node: SCNNode, image: Bool, identifier: Int, opacity: CGFloat = 0.25){
    
        self.planeAnchor = anchor
    
        self.planeGeometry = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z))
        let planeNode = SCNNode(geometry: planeGeometry)
    
        super.init()
    
        if image{
    
            let planeMaterial = SCNMaterial()
            planeMaterial.diffuse.contents = UIImage(named: DEFAULT_IMAGE)
    
            self.planeGeometry.materials = [planeMaterial]
        }
    
        planeNode.simdPosition = float3(self.planeAnchor.center.x, 0, self.planeAnchor.center.z)
        planeNode.eulerAngles.x = -.pi / 2
        planeNode.opacity = opacity
    
        node.addChildNode(planeNode)
        node.name = "\(NAME) \(identifier)"
    
    }
    
    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
    
    deinit {
        #if DEBUG
        print("Plane Node Deinitialized")
        #endif
    }
    
    /// Updates The Size Of The Plane As & When The ARPlaneAnchor Has Been Updated
    ///
    /// - Parameter anchor: ARPlaneAnchor
    func update(_ anchor: ARPlaneAnchor) {
    
        self.planeAnchor = anchor
    
        self.planeGeometry.width = CGFloat(anchor.extent.x)
        self.planeGeometry.height = CGFloat(anchor.extent.z)
    
        self.position = SCNVector3Make(anchor.center.x, 0.01, anchor.center.z)
    
        returnPlaneInfo()
    }
    
    //-----------------------
    //MARK: Plane Information
    //-----------------------
    
    /// Returns The Size Of The ARPlaneAnchor & Its Alignment
    func returnPlaneInfo(){
    
        let widthOfPlane = self.planeAnchor.extent.x
        let heightOfPlane = self.planeAnchor.extent.z
    
        var planeAlignment: String!
    
        switch planeAnchor.alignment {
    
        case .horizontal:
            planeAlignment = "Horizontal"
        case .vertical:
            planeAlignment = "Vertical"
        }
    
        #if DEBUG
        print("""
            Width Of Plane =  \(String(format: "%.2fm", widthOfPlane))
            Height Of Plane =  \(String(format: "%.2fm", heightOfPlane))
            Plane Alignment = \(planeAlignment)
            """)
        #endif
    
        self.widthInfo = String(format: "%.2fm", widthOfPlane)
        self.heightInfo = String(format: "%.2fm", heightOfPlane)
        self.alignmentInfo = planeAlignment
      }
    
    }
    

    【讨论】:

    • 嗨,乔希,感谢您的提示!我在定义平面的第一行出现错误:Type of expression is ambiguous without more context 有什么想法吗?
    • 你的 PlaneNode 类是什么样的?
    • 另外,只要你有时间。我在控制台中收到此错误:When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug. 这仅在根据您的代码进行更改后才开始发生。知道这个错误可能指的是什么吗?再次感谢!
    • 这是在讨论界面生成器中的某些内容,或者您​​设置场景的方式。当我运行它时,控制台中没有任何问题:)
    • 好的,感谢您缩小范围。我再看看我的代码。谢谢乔希!
    猜你喜欢
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 2018-11-27
    • 1970-01-01
    • 2021-05-03
    相关资源
    最近更新 更多