Getting location of tap on SCNSphere - Swift (SceneKit) / iOS

1.5k Views Asked by At

I want to create a sample application that allows the user to get information about continents on a globe when they tap on them. In order to do this, I need to figure out the location where a user taps on an SCNSphere object in a scene (SceneKit). I attempted to do it like this:

import UIKit
import SceneKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = SCNScene()

        /* Lighting and camera added (hidden)*/

        let earthNode = SCNSphere(radius: 1)
        /* Added styling to the Earth (hidden)*/
        earthNode.name = "Earth"
        scene.rootNode.addChildNode(earthNode)

        let sceneView = self.view as! SCNView
        sceneView.scene = scene

        sceneView.allowsCameraControl = true

        // add a tap gesture recognizer
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        sceneView.addGestureRecognizer(tapGesture)

    }


    @objc func handleTap(_ gestureRecognize: UIGestureRecognizer) {
        // retrieve the SCNView
        let sceneView = self.view as! SCNView

        // check what nodes are tapped
        let p = gestureRecognize.location(in: scnView)
        let hitResults = sceneView.hitTest(p, options: [:])
        // check that we clicked on at least one object
        if hitResults.count > 0 {
            // retrieved the first clicked object
            let result: SCNHitTestResult = hitResults[0]

            print(result.node.name!)
            print("x: \(p.x) y: \(p.y)") // <--- THIS IS WHERE I PRINT THE COORDINATES


        }
    }

}

When I actually run this code however and click on an area on my sphere, it prints out the coordinates of the tap on the screen instead of where I tapped on the sphere. For example, the coordinates are the same when I tap on the center of the sphere, and when I tap it in the center again after rotating the sphere.

I want to know where on the actual sphere I pressed, not just where I click on the screen. What is the best way that I should go about this problem?

1

There are 1 best solutions below

2
On BEST ANSWER

In the hitResult, you can get result.textureCoordinates which tells you the point in your map textures. From this point, you are supposed to know the location of your map as the map should have coordinations which was mapped to textures.

 @objc func handleTap(_ gestureRecognize: UIGestureRecognizer) {
    // retrieve the SCNView
    let sceneView = self.view as! SCNView

    // check what nodes are tapped
    let p = gestureRecognize.location(in: scnView)
    let hitResults = sceneView.hitTest(p, options: [:])
    // check that we clicked on at least one object
    if hitResults.count > 0 {
        // retrieved the first clicked object
        let result: SCNHitTestResult = hitResults[0]

        print(result.node.name!)
        print(result.textureCoordinates(withMappingChannel 0)) // This line is added here. 
        print("x: \(p.x) y: \(p.y)") // <--- THIS IS WHERE I PRINT THE COORDINATES


    }
}