在SceneKit iOS中使用平移手势旋转节点

时间:2017-06-27 13:11:05

标签: ios swift rotation scenekit matrix-multiplication

我使用以下代码使用平移手势旋转节点。我喜欢只在y轴上旋转我的节点。

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

}

这适用于Euler设置为(x:0,y:0,z:0)的节点。但我的节点有Euler(x:-90,y:0,z:0)。对于我上面的Euler值,代码以错误的角度旋转对象。如何使用我/不同的Euler值旋转节点?

3 个答案:

答案 0 :(得分:4)

我认为你可能会过度复杂化你需要做的事情。

在我的示例中,我创建了SCNNode SCNBox Geometry,并根据您的示例设置Euler Angles :( x:-90,y:0,z:0 )。

您需要做的第一件事是创建一个变量来存储围绕YAxis的rotationAngle:

var currentAngleY: Float = 0.0

然后尝试使用此功能,以便围绕YAxis旋转节点(顺便说一下,这可以正常工作):

 /// 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)
}

希望它有所帮助...

答案 1 :(得分:0)

旋转矢量应如下所示;

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

x,y,z是归一化的单位向量 w是弧度

检查你的数学

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

可能检查x,y的值应该类似于

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

答案 2 :(得分:0)

以下是如何做你想做的事情,这恰好是唯一的方法:

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];

        }
    }

以下是它的工作原理:BOOL用于防止在设备屏幕上上下滑动手指导致的多种平移手势调用,因为此特定代码一次将立方体旋转90° 。当您开始新手势时,它将允许您再次运行与旋转相关的代码。

translationInView方法使用两次:一次确保您想要旋转立方体,方法是在旋转立方体之前在任一方向上要求至少10的距离,第二次确定是否在滑动向上或向下(通过评估翻译价值是正还是负)。

由于我的立方体只是上下旋转,我向{/ 1}}向量的(x)值加上或减去了90°;我将剩余的eulerAngles值放在各自的位置。

所有内容都放置在SCNTransaction内部,以设置旋转动画,并控制旋转动画的持续时间。

我确实尝试过所有其他类型的旋转方法,即使是核心动画等等 - 这就是所有这些都可以让你来回旋转立方体等,而不会发生奇怪的事情。我有一个使用这个代码的应用程序,它工作正常。如果您在将其集成到自己的应用程序中时遇到问题,我很乐意随时将应用程序的代码转发给您。