Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ios - ARKit - How to create rotate object gesture function?

Tags:

ios

swift

arkit

I'm new in ARKit. I want to create a function to rotate object. This is my code about drag and rotate object:

// Rotate object
@objc func rotateRecognized(sender: UIPanGestureRecognizer) {
    let sceneView = sender.view as! ARSCNView
    let swipeLocation = sender.location(in: sceneView)
    let hitTest = sceneView.hitTest(swipeLocation)
    if !hitTest.isEmpty {
        sender.minimumNumberOfTouches = 2
        let results = hitTest.first!
        let node = results.node
        let xPan = sender.velocity(in: sceneView).x/10000
        node.runAction(SCNAction.rotateBy(x: 0, y: xPan, z: 0, duration: 0.1))
    }
}

// Drag object
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    //1. Get The Current Touch Point
    guard let currentTouchPoint = touches.first?.location(in: self.sceneView),
        //2. Get The Next Feature Point Etc
        let hitTest = sceneView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

    //3. Convert To World Coordinates
    let worldTransform = hitTest.worldTransform

    //4. Set The New Position
    let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

    //5. Apply To The Node
    self.sceneView.scene.rootNode.enumerateChildNodes{ (node, _) in
       node.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)
    }

}

When I drag an object, it's work fine. But when I rotate object by swipe with two fingers, the object cannot rotate until I remove the touchesMoves method. How to fix this issue? Thank you.

like image 279
Duc Phan Avatar asked Mar 25 '18 08:03

Duc Phan


1 Answers

I think it would be best to approach this using GestureRecognizers rather than a combination of both touches and gestures together.

Let's have a look therefore, at how we could tackle this.

You already have the functionality to drag an SCNNode which could quite easily be converted into a UIPanGesture, and you want a function to rotate an SCNNode around it's YAxis which we can quite easily do with a UIRotationGestureRecognizer.

In my example I have an SCNNode called currentNode, although yours will of course be different.

First we will create two variables:

//Store The Rotation Of The CurrentNode
var currentAngleY: Float = 0.0

//Not Really Necessary But Can Use If You Like 
var isRotating = false

Then we will create two gestureRecognizers in viewDidLoad:

 let panGesture = UIPanGestureRecognizer(target: self, action: #selector(moveNode(_:)))
 self.view.addGestureRecognizer(panGesture)

 let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateNode(_:)))
 self.view.addGestureRecognizer(rotateGesture)

Having done this, we then need to create our functions.

The first will handle dragging the currentNode e.g:

/// Rotates An Object On It's YAxis
///
/// - Parameter gesture: UIPanGestureRecognizer
@objc func moveNode(_ gesture: UIPanGestureRecognizer) {

    if !isRotating{

    //1. Get The Current Touch Point
    let currentTouchPoint = gesture.location(in: self.augmentedRealityView)

    //2. Get The Next Feature Point Etc
    guard let hitTest = self.augmentedRealityView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

    //3. Convert To World Coordinates
    let worldTransform = hitTest.worldTransform

    //4. Set The New Position
    let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

    //5. Apply To The Node
    currentNode.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)

    }
}

The second rotating it around it's YAxis:

/// Rotates An SCNNode Around It's YAxis
///
/// - Parameter gesture: UIRotationGestureRecognizer
@objc func rotateNode(_ gesture: UIRotationGestureRecognizer){

    //1. Get The Current Rotation From The Gesture
    let rotation = Float(gesture.rotation)

    //2. If The Gesture State Has Changed Set The Nodes EulerAngles.y
    if gesture.state == .changed{
        isRotating = true
        currentNode.eulerAngles.y = currentAngleY + rotation
    }

    //3. If The Gesture Has Ended Store The Last Angle Of The Cube
    if(gesture.state == .ended) {
        currentAngleY = currentNode.eulerAngles.y
        isRotating = false
    }
}

This is a very crude example and you would need to look at the different gestureStates etc, but hopefully it should point you in the right direction...

like image 159
BlackMirrorz Avatar answered Nov 11 '22 17:11

BlackMirrorz