skip to Main Content

I created a SCNView and want to use a UITapGestureRecognizer to move SCNNode‘s around the view; however, the code I implemented doesn’t seem to be working. The nodes move sometimes, but they never move to the correct spot. Does anyone know what I am doing wrong here?

@objc func handleTapGesture(_ gesture: UITapGestureRecognizer) {
        let location = gesture.location(in: scnView)
        
        guard let result = self.scnView?.hitTest(location, options: nil).first else { return }
        let transform = result.simdModelTransform
        let newPosition = SCNVector3(transform.columns.3.x, node.position.y, transform.columns.3.z)
        
        node.position = newPosition
    }

2

Answers


  1. Looks like you are confused about usage of hitTest in SCNView. Firstly, note that hitTest(_:options:) will search for objects/nodes in the given scene corresponding to the ray-cast hits from point of touch. This explains why sometimes your code doesn’t work because the hit test results will be empty in case the objects are not found.

    To make things work as expected, you must project the point from CGPoint into scene using following code which also requires you to provide depth.

    func pointToSCNVector3(view: SCNView, depth: Float, point: CGPoint) -> SCNVector3 {
        let projectedOrigin = view.projectPoint(SCNVector3Make(0, 0, depth))
        let locationWithz   = SCNVector3Make(Float(point.x), Float(point.y), projectedOrigin.z)
        return view.unprojectPoint(locationWithz)
    }
    

    then use the output to set the node position

    @objc func handleTapGesture(_ gesture: UITapGestureRecognizer) {
            let location = gesture.location(in: scnView)
            node.position = pointToSCNVector3(view: scnView, depth: 50, point: location)
        }
    
    Login or Signup to reply.
  2. You can also try using PanGesture as well.
    Let me give you sample code for the same.

    let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(panGesture:)))
    view.addGestureRecognizer(panRecognizer)
    
    
    @objc func handlePan(panGesture: UIPanGestureRecognizer) {
    
    
     guard let view = view as? SCNView else { return }
    let location = panGesture.location(in: self.view)
     switch panGesture.state {
    case .began:
     guard let hitNodeResult = view.hitTest(location, options: nil).first else { return }
    panStartZ = CGFloat(view.projectPoint(lastPanLocation!).z)
    lastPanLocation = hitNodeResult.worldCoordinates
    case .changed:
     let worldTouchPosition = view.unprojectPoint(SCNVector3(location.x, location.y, panStartZ!))
    let movementVector = SCNVector3(
     worldTouchPosition.x - lastPanLocation!.x,
    worldTouchPosition.y - lastPanLocation!.y,
    worldTouchPosition.z - lastPanLocation!.z)
    geometryNode.localTranslate(by: movementVector)
    self.lastPanLocation = worldTouchPosition
    default:
     break
    }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search