SK3DNode hitTest not working in SpriteKit/SceneKit

I have this minimum repro code:


import SpriteKit
import GameplayKit

class MyGameScene3D: SCNScene {
  
  weak var node3D: MyNode3D!
  
  override init() {
    super.init()
    
    background.contents = UIColor.green
    
    let playground = SCNNode()
    playground.boundingBox = (
      min: SCNVector3(x: 0, y: 0, z: 0),
      max: SCNVector3(x: 10, y: 10, z: 10))
    let box = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
    box.position = SCNVector3(x: 5, y: 5, z: 5)
    playground.addChildNode(box)
    
    playground.position = SCNVector3(x: 0, y: 0, z: 0)
    rootNode.addChildNode(playground)
    
    let light = SCNLight()
    light.type = .ambient
    let lightNode = SCNNode()
    lightNode.light = light
    rootNode.addChildNode(lightNode)
    
    let camera = SCNCamera()
    let cameraNode = SCNNode()
    cameraNode.camera = camera
    cameraNode.eulerAngles = SCNVector3(x: -3.14/2, y: 0, z: 0)
    cameraNode.position = SCNVector3(x: 5, y: 11, z: 5)
    rootNode.addChildNode(cameraNode)
    
  }
  
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  func handleTouchBegan(_ location: CGPoint) {
    let res = node3D.hitTest(location)
    print(res)
  }
}

class MyNode3D: SK3DNode {
  
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first!
    let scene = scnScene as! MyGameScene3D
    let location = touch.location(in: self)
    print(location)
    scene.handleTouchBegan(location)
  }
  
}

class GameScene: SKScene {
  
  
  init() {
    super.init(size: CGSize(width: 500, height: 1000))
    self.backgroundColor = .red
    let node3D = MyNode3D()
    let scene3D = MyGameScene3D()
    node3D.scnScene = scene3D
    scene3D.node3D = node3D
    node3D.isUserInteractionEnabled = true
    node3D.viewportSize = CGSize(width: 100, height: 200)
    node3D.position = CGPoint(x: 50, y: 100)
    addChild(node3D)
    
    
    let up = SKSpriteNode(color: .blue, size: CGSize(width: 500, height: 10))
    up.anchorPoint = CGPoint(x: 0, y:0)
    up.position = CGPoint(x:0, y:200)
    addChild(up)
    
    let right = SKSpriteNode(color: .gray, size: CGSize(width: 10, height: 500))
    right.anchorPoint = CGPoint(x:0,y: 0)
    right.position = CGPoint(x:100, y:0)
    addChild(right)
    
  }
  
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

Basically, I have a SK3DNode of size 100x200, positioned at lower left corner of the screen (see screenshot below).

Then in this SK3DNode, I have a SCNScene, where I put a 10x10x10 Playground node at position (0, 0, 0). Then I put a camera node right at the top of the Playground at position (5, 11, 5), and the camera looks down along the -y axis, with euler angle = (-90, 0, 0).

Then in this Playground, I put a small box of size 1x1x1, at the center of the Playground at (5, 5, 5).

The 2 long bars (gray & blue) are just there to indicate the boundary of the SK3DNode.

The result rendering is correct (see screenshot below). However, I can't get the hit test working. I tap on the center 1x1x1 box on screen, get the right coordinate printed out, but the hit test result is empty. I want to be get the center 1x1x1 box when hitting there. How can I do so?

https://i.sstatic.net/OlrY8TX1.png

Update:

I tried to loop through all the pixels from -2000 to 2000, and still no hit:


  func handleTouchBegan(_ location: CGPoint) {
    
    for x in -2000...2000 {
      print("handling x: \(x)")
      for y in -2000...2000 {
        let res = node3D.hitTest(location)
        if !res.isEmpty {
          print("\(x), \(y), \(res)")
        }
      }
    }
    print("Done")
  }
Answered by DTS Engineer in 812210022

Hello @linzhaocha,

At it's core, this appears to be a coordinate space issue, I recommend that you apply the debugging techniques mentioned in TN3124: Debugging coordinate space issues to try and debug the problem.

Best regards,

Greg

Hello @linzhaocha,

At it's core, this appears to be a coordinate space issue, I recommend that you apply the debugging techniques mentioned in TN3124: Debugging coordinate space issues to try and debug the problem.

Best regards,

Greg

SK3DNode hitTest not working in SpriteKit/SceneKit
 
 
Q