【问题标题】:How to detect which SCNNode has been touched ARKit如何检测哪个 SCNNode 被触摸了 ARKit
【发布时间】:2018-03-06 23:42:25
【问题描述】:

我在 SCNode 命中检测方面遇到了一些问题。我需要检测在具有 SCNNode 的场景中触摸了哪个对象,我已经实现了这段代码,但是当我触摸对象时它似乎崩溃了,但当我触摸场景视图的其余部分时它工作得很好。

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 (bottleNode?.contains(result.node))! { //bottleNode is declared as  SCNNode? and it's crashing here
                print("match")
            }

        }
    }

【问题讨论】:

    标签: swift scenekit arkit scnnode


    【解决方案1】:

    这里有多个问题,现有的答案只是解决其中的一部分。

    1. 从您发布的代码中不清楚当此方法运行时bottleNode 是否可以为零。当它的值为 nil 时,通过可选项(bottle?.contains 中的 ?)调用方法会静默失败——导致整个表达式结果包装在值为 nil 的 Optional 中——但你有括号和强制展开围绕整个表达式,所以 nil-unwrap 会崩溃。

    2. contains(_:) 不是 SCNNode 上的方法。目前尚不清楚您的bottleNode 可能是什么类型,您甚至可以编写此方法调用而不会出现编译器错误......但如果bottleNode 实际上是SCNNode 并且您已经完成了一些类型擦除/Any-强制转换 goop 以允许编译调用,由于方法不存在,调用将在运行时失败。

    如果您使用bottleNode.contains 行的目标是确定命中测试结果是bottleNode 本身还是其子节点,我建议您定义和使用这样的扩展方法:

    extension SCNNode {
        func hasAncestor(_ node: SCNNode) -> Bool {
            if self === node {
                return true // this is the node you're looking for
            }
            if self.parent == nil {
                return false // target node can't be a parent/ancestor if we have no parent
            } 
            if self.parent === node {
                return true // target node is this node's direct parent
            }
            // otherwise recurse to check parent's parent and so on
            return self.parent.hasAncestor(node)
        }
    }
    
    // in your touchesBegan method...
    if let bottleNode = bottleNode, result.node.hasAncestor(bottleNode) { 
        print("match")
    }
    

    如果您的目标是确定result.node 是否位于bottleNode 的边界框内或重叠(无论节点层次结构如何),那么回答该问题会稍微复杂一些。 boundingSphere 中的简单 position 检查非常容易,或者如果您正在寻找包含/重叠,octree 可能会有所帮助。

    【讨论】:

    • 1.问题中确实没有提到,但是如果您真的想假设在专门为该节点执行命中测试之前它可以为 nil,那么在执行命中测试之前实际执行该检查是有意义的。
    • P2.除了无效的包含方法之外,没有理由假设bottleNode 具有子节点,但如果是这种情况,使用自定义扩展来遍历结果节点的父节点而不是简单地检查bottlenode 子节点是否包含任何附加值结果节点? (即瓶节点上的 enumerateHierarchy 将避免检查结果节点的所有父节点)。我确定在复制并粘贴您的代码后它可以解决,但这将是由于扩展的 self==node 部分,所以我认为这不应该是公认的答案。
    • @Xartec 好点。由于不知道有问题的节点层次结构,我选择了一种算法效率一般的解决方案。沿着父层次结构向上移动受限于节点树的高度,但搜索目标节点的子子树受限于该子树的整个宽度。对于任意大树中的任何点,最坏情况下的子树大小可能远大于返回根的高度。但值得考虑的是您希望在您的应用中拥有的节点层次结构——如果它非常平坦,针对测试节点的简单指针相等性测试可能就足够了。
    【解决方案2】:

    可能是,bottleNode 为零。哪条线路导致崩溃?在比较之前检查bottleNode是否存在:

    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 bottleNode = bottleNode, bottleNode == result.node { //bottleNode is declared as  SCNNode? and it's crashing here
                    print("match")
                }
    
            }
        }
    

    【讨论】:

      【解决方案3】:

      您目前正在测试您的 SCNNode 是否“包含”来自 hittest 结果的节点,而您应该简单地比较它们,即 if (bottlenode == result.node)...

      【讨论】:

        【解决方案4】:

        您是否真的创建了bottleNode?如果bottleNode 为nil,则表达式bottleNode?.contains(result.node) 也将为nil,所以当你强制解包时,它会抛出错误。

        如果您知道bottleNode 将始终被定义,那么它不应该是可选的。如果您不知道,则需要在使用之前检查它是否存在。这应该做你想做的事:

        if let bottleNode = bottleNode, bottleNode.contains(result.node) {
        

        请注意,如果 bottleNode 不存在,此测试将静默失败。

        【讨论】:

        • Contains 不是 SCNNode 的方法。
        猜你喜欢
        • 2018-07-28
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多