13

I have a simple SCNNode in ARKit and I am trying to drag it wherever I moved my finger on the phone. Here is my code.

 @objc func pan(recognizer :UIGestureRecognizer) {

        guard let currentFrame = self.sceneView.session.currentFrame else {
            return
        }

        var translation = matrix_identity_float4x4
        translation.columns.3.z = -1.5

        let sceneView = recognizer.view as! ARSCNView
        let touchLocation = recognizer.location(in: sceneView)

        let hitTestResult = sceneView.hitTest(touchLocation, options: [:])

        if !hitTestResult.isEmpty {

            print("hit result")

            guard let hitResult = hitTestResult.first else {
                return
            }

            let node = hitResult.node

            node.simdTransform = matrix_multiply(currentFrame.camera.transform, translation)
        }
    }

The problem is that the drag is very slow and not smooth.

John Tracid
  • 3,836
  • 3
  • 22
  • 33
john doe
  • 9,220
  • 23
  • 91
  • 167
  • Take a look on this question: https://stackoverflow.com/questions/6672677/how-to-use-uipangesturerecognizer-to-move-object-iphone-ipad. You should work with pan gesture states correctly. – John Tracid Jul 03 '17 at 08:31
  • Did this work for you? – mergesort Jul 16 '17 at 23:09
  • Wondering if you managed to figure something out John Doe. – Alan Aug 17 '17 at 08:19
  • Did you achieve this? I am exactly looking for the same. – Vidhya Sri May 25 '18 at 06:47
  • Possible duplicate of [ARKIT: Move Object with PanGesture (the right way)](https://stackoverflow.com/questions/50131675/arkit-move-object-with-pangesture-the-right-way) – Susan Kim Jun 26 '19 at 08:20
  • Checkout my answer to the thread @SusanKim linked, and post any further question as comment there as that should be a relatively good method for dragging objects – A. Claesson Jun 26 '19 at 14:47

3 Answers3

7

I handle translation with PanGesture like this. The division by 700 is to smooth and adjust speed of movement, I reached to that value by trial or error, you may want to experiment with it

@objc func onTranslate(_ sender: UIPanGestureRecognizer) {
    let position = sender.location(in: scnView)
    let state = sender.state

    if (state == .failed || state == .cancelled) {
        return
    }

    if (state == .began) {
        // Check it's on a virtual object
        if let objectNode = virtualObject(at: position) {
            // virtualObject(at searches for root node if it's a subnode
            targetNode = objectNode
            latestTranslatePos = position
        }

    }
    else if let _ = targetNode {

        // Translate virtual object
        let deltaX = Float(position.x - latestTranslatePos!.x)/700
        let deltaY = Float(position.y - latestTranslatePos!.y)/700

        targetNode!.localTranslate(by: SCNVector3Make(deltaX, 0.0, deltaY))

        latestTranslatePos = position

        if (state == .ended) {
            targetNode = nil
        }
    }
}
leandrodemarco
  • 1,552
  • 1
  • 15
  • 22
  • This works in 2 axis but when i rotate the object with fingers using UIRotationGestureRecognizer and then try to move it, it is not working correctly. When i move the finger from left to right, it is moving SCNode in opposite direction. Is there a way to move the SCNode correctly with finger movement irrespective of the rotation? – Vidhya Sri May 23 '18 at 06:48
  • Hi @yaali. I'm just taking a guess here, but maybe if you use something that changes the position regarding to the parent node or the world origin you can correct it instead of `localTranslate:by`. Perhaps `worldPosition` or `position` – leandrodemarco Jun 05 '18 at 19:26
  • @leandrodemarco : can you please help me to understand what is "*virtualObject(at: position)*" and what it does ? – Wolverine Oct 12 '18 at 07:18
  • virtualObject what is this – Abhishek Thapliyal Dec 26 '18 at 09:01
  • still works like a champ! thanks! – Joel Mar 09 '23 at 10:13
1

Had the same issue. Using a SCNTransaction did the trick for me.

@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
    [...]

    SCNTransaction.begin()
    SCNTransaction.animationDuration = 0
    imagePlane.position.x = hitTestResult.localCoordinates.x
    imagePlane.position.y = hitTestResult.localCoordinates.y
    SCNTransaction.commit()
}
d4Rk
  • 6,622
  • 5
  • 46
  • 60
0

I had a similar problem. Whilst you should use John's advice in the comments and use the pan gesture states correct (Began, Changed, Ended), I think the issue might be that you are grabbing the hitResult.node when you should be grabbing the parent of the node, or even the parent's parent, etc... I've had this issue and ended up fixing it by going up parent levels until the entire object was being selected instead of a part of it.

Alan
  • 1,132
  • 7
  • 15