Rotate a node using pan gesture in SceneKit iOS

北战南征 提交于 2019-12-21 20:21:53

问题


I am using the below code to rotate a node using the pan gesture. I like to rotate my node only in the y-axis.

let translation = gestureRecognize.translation(in: gestureRecognize.view!)

let x = Float(translation.x)
let y = Float(-translation.y)
let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0

var rotationVector = SCNVector4()
rotationVector.x = 0.0
rotationVector.y = x
rotationVector.z = 0.0
rotationVector.w = anglePan


node.rotation = rotationVector

if(gestureRecognize.state == UIGestureRecognizerState.ended) {
    let currentPivot = node.pivot
    let changePivot = SCNMatrix4Invert( node.transform)

    node.pivot = SCNMatrix4Mult(changePivot, currentPivot)
    node.transform = SCNMatrix4Identity

}

This works for nodes with Euler set to (x: 0, y: 0, z: 0). But my node has Euler (x: -90, y: 0, z: 0). For my Euler values above code rotates the object in the wrong angle. How can I rotate a node with my/different Euler values?


回答1:


I think you might be overcomplicating what you need to do here.

In my example, I have created an SCNNode with an SCNBox Geometry and set it's Euler Angles as per your example: (x: -90, y: 0, z: 0).

The 1st thing you need to do, is create a variable to store the rotationAngle around the YAxis:

var currentAngleY: Float = 0.0

Then try this function in order to rotate your node around the YAxis (which works fine by the way):

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

        guard let nodeToRotate = currentNode else { return }

        let translation = gesture.translation(in: gesture.view!)
        var newAngleY = (Float)(translation.x)*(Float)(Double.pi)/180.0
        newAngleY += currentAngleY

        nodeToRotate.eulerAngles.y = newAngleY

        if(gesture.state == .ended) { currentAngleY = newAngleY }

        print(nodeToRotate.eulerAngles)
}

Hope it helps...




回答2:


The rotation vector should look like this;

rotation = SCNVector4(x: 0, y: 1, z: 0, w: some_angle_in_radians)

x,y,z is a normalized unit vector w is in radians

check your math

let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0

probably check values of x,y, should be something like

let anglePan = (sqrt(pow(x*deg2rd,2)+pow(y*deg2rad,2)))



回答3:


Here's how to do what you want, which happens to be the only way to do it:

BOOL shouldRotateCube;    
- (IBAction)handlePanGesture:(UIPanGestureRecognizer *)sender {
        if (sender.state == UIGestureRecognizerStateBegan)
        {
            shouldRotateCube = TRUE;
        } else if (sender.state == UIGestureRecognizerStateChanged && shouldRotateCube
                   && fabs([sender translationInView:sender.view].y) > 10.0)
        {
            shouldRotateCube = FALSE;
            [SCNTransaction begin];
[SCNTransaction setCompletionBlock:^{
    [SCNTransaction begin];
    [SCNTransaction setAnimationDuration:0.15];
    SCNVector3 nodeAngles = [node eulerAngles];
        [node setEulerAngles:SCNVector3Make(nodeAngles.x + (([sender translationInView:sender.view].y > 0.0) ? degreesToRadians(90) : degreesToRadians(-90)), nodes[i].rotation.y, nodes[i].rotation.z)];
    }
    [SCNTransaction commit];
}];
[SCNTransaction commit];

        }
    }

Here's how it works: a BOOL is used to prevent the multiplicity of pan gesture calls that results from swiping your finger up and down on your device's screen, since this particular code rotates a cube 90° at a time. When you begin a new gesture, then it will allow you to run the rotation-related code again.

The translationInView method is used twice: once to make sure you intend to rotate the cube by requiring a distance of at least 10 in either direction before rotating the cube, and a second time to determine whether you are swiping up or down (by evaluating whether the translation value is positive or negative).

Since my cube is only being rotated up and down, I either added or subtracted 90° to/from the (x) value of the eulerAngles vector; I placed the remaining eulerAngles values in their respective positions.

Everything was placed inside an SCNTransaction to animate the rotation, and to control the duration of the rotation animation.

I've literally tried every other kind of rotation method available, even those in Core Animation, etc .—this is all that allows you to rotate a cube, etc., back and forth without weird things happening. I have an app that uses this very code, and it works fine. If you have trouble integrating it into your own app, I will gladly forward the code for my app to you at anytime.



来源:https://stackoverflow.com/questions/44781184/rotate-a-node-using-pan-gesture-in-scenekit-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!