Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect which SCNNode has been touched ARKit

I'm having some troubles with SCNode hit detection. I need to detect which object was touched in the scene having a SCNNode, I have implemented this piece of code but it seems crashing when I'm touching the object but working good when I'm touching the rest of the sceneView.

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")
            }

        }
    }
like image 461
Pietro Messineo Avatar asked Sep 25 '17 21:09

Pietro Messineo


3 Answers

There are multiple problems here, and the existing answers are addressing only some of them.

  1. It's unclear from the code you've posted whether bottleNode can be nil when this method runs. Calling a method through the optional (the ? in bottle?.contains) when its value is nil would fail silently — causing the entire expression result to wrap in an Optional whose value is nil — but you've got parens and a force unwrap around the whole expression, so the nil-unwrap would crash.

  2. contains(_:) is not a method on SCNNode. It's unclear what type your bottleNode could be that you could even write this method call without getting compiler errors... but if bottleNode actually is an SCNNode and you've done some type-erasing/Any-casting goop to allow the call to compile, the call would fail at runtime due to the non-existent method.

If your goal with the bottleNode.contains line is to determine whether the hit test result is either bottleNode itself or a child node thereof, I'd recommend defining and using an extension method like this:

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")
}

If instead your goal is to determine whether result.node lies within or overlaps the bounding box of bottleNode (regardless of node hierarchy), answering that question is a little more complicated. A simple position within boundingSphere check is pretty easy, or if you're looking for containment/overlap, an octree might help.

like image 83
rickster Avatar answered Oct 17 '22 06:10

rickster


It could be that, bottleNode is nil. What line is causing the crash? Check if bottleNode exists before the comparison:

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")
            }

        }
    }
like image 4
Nana Ghartey Avatar answered Oct 17 '22 06:10

Nana Ghartey


You are currently testing if your SCNNode “contains” the node from the hittest result while you should instead simply compare them, i.e. if (bottlenode == result.node)...

like image 1
Xartec Avatar answered Oct 17 '22 07:10

Xartec