5
votes

I am trying to move a node in SceneKit by touch. I am using the code here: Move a specific node in SceneKit using touch

The issue that I am having is that every time I start a panGesture, the object I touch goes to the left corner of the scene to start the move. Moving it from that position and releasing are ok, just the issue that at every start of panning, the object resets from the left corner. If I zoom out, it resets itself from the corner of this new zoom level.

My code is:

func CGPointToSCNVector3(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)
}
func dragObject(sender: UIPanGestureRecognizer){
    if(movingNow){
        let translation = sender.translationInView(sender.view!)
        var result : SCNVector3 = CGPointToSCNVector3(objectView, depth: tappedObjectNode.position.z, point: translation)
        tappedObjectNode.position = result
    }
    else{
        let hitResults = objectView.hitTest(sender.locationInView(objectView), options: nil)
        if hitResults.count > 0 {
            movingNow = true
        }
    }
    if(sender.state == UIGestureRecognizerState.Ended) {
    }
}

and

override func viewDidLoad() {
    super.viewDidLoad()
    let scnView = objectView
    scnView.backgroundColor = UIColor.whiteColor()
    scnView.autoenablesDefaultLighting = true
    scnView.allowsCameraControl = true

i am temporarily disabling the allowsCameraControl's panning functions before dragObject is called by doing this:

globalPanRecognizer = UIPanGestureRecognizer(target: self, 
    action:#selector(ViewController.dragObject(_:)))
objectView.addGestureRecognizer(globalPanRecognizer)

These are the values inside the first call to CGPointToSCNVector3 :

  • initial value of tappedObjectNode: SCNVector3(x: 0.100000001, y: 0.100000001, z: 3.0)
  • projectedOrigin : SCNVector3(x: 261.613159, y: 285.530396, z: 0.949569583) - this is abnormally big
  • value returned by CGPointToSCNVector3 : SCNVector3(x: 1.03418088, y: 1.9734658, z: 4.64346933)

I have played with different variations of CGPointToSCNVector3 but no luck. What is the cause of this behavior? Thanks,

2
hello, so it is not due to the line allowsCameraControl because I commented the line and get the same behavior. I also have no idea how you commented the code, I have been trying to do that. ThanksNicoara Talpes
Same behavior for the @rickster code that is linked to in a comment at the SO link I mentioned. if(movingNow){ let translation = sender.translationInView(sender.view!) var offset = objectView.unprojectPoint(SCNVector3Make(Float(translation.x), Float(translation.y), globalProjectedOrigin.z))//step 5 tappedObjectNode.position.x = globalOffset.x + offset.x // step 6, and y and z } else{ let hitResults = objectView.hitTest(sender.locationInView(objectView), options: nil) ..next comment }Nicoara Talpes
continued: ` if hitResults.count > 0 { globalWorldCoordinates = hitResults[0].worldCoordinates // step 2 globalProjectedOrigin = objectView.projectPoint(globalWorldCoordinates)//step 3 globalOffset.x = globalWorldCoordinates.x - tappedObjectNode.position.x // step 4, and y and z movingNow = true } ` (can't figure out code formatting here , sorry)Nicoara Talpes

2 Answers

3
votes

The solution was to change sender.translationInView(sender.view!) to sender.translationInView(self.view!)

-1
votes

Swift 4.1 / Xcode 9.3 / iOS 11.3

// node that you want the user to drag
var tappedObjectNode = SCNNode()

// the SCNView
@IBOutlet weak var sceneView: SCNView!

// the scene
let scene = SCNScene()

//helper
func CGPointToSCNVector3(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)
}

// gesture handler
var movingNow = false
@objc func dragObject(sender: UIPanGestureRecognizer){
if(movingNow){
        let translation = sender.translation(in: sender.view!)
        var result : SCNVector3 = CGPointToSCNVector3(view: sceneView, depth: tappedObjectNode.position.z, point: translation)    
        tappedObjectNode.position = result
    } else {
        // view is the view containing the sceneView
        let hitResults = sceneView.hitTest(sender.location(in: view), options: nil)
        if hitResults.count > 0 {
            movingNow = true
        }
    }
}


// in viewDidLoad
sceneView.scene = scene

let panner = UIPanGestureRecognizer(target: self, action: #selector(dragObject(sender:)))
sceneView.addGestureRecognizer(panner)