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

Rotate a node using pan gesture in SceneKit iOS

我正在使用以下代码通过平移手势旋转节点。我喜欢只在 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) 的节点。但是我的节点有欧拉(x:-90,y:0,z:0)。对于我上面的欧拉值,代码以错误的角度旋转了对象。如何旋转具有 my/different 欧拉值的节点?[​​=12=]

旋转矢量应如下所示;

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

这里是如何做你想做的,这恰好是唯一的方法:

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°一个时间。当您开始一个新手势时,它将允许您再次 运行 rotation-related 代码。

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

由于我的立方体只是上下旋转,所以我将 eulerAngles 向量的 (x) 值加上或减去 90° to/from;我将剩余的 eulerAngles 个值放在它们各自的位置。

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

我确实尝试过所有其他可用的旋转方法,甚至是 Core Animation 等中的旋转方法——这就是允许您来回旋转立方体等的所有方法,而不会发生奇怪的事情。我有一个使用此代码的应用程序,并且运行良好。如果您无法将其集成到您自己的应用程序中,我很乐意随时将我的应用程序代码转发给您。

我认为你可能把这里需要做的事情复杂化了。

在我的示例中,我创建了一个带有 SCNBox 几何体的 SCNNode 并根据您的示例将其设置为 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)
}

希望对您有所帮助...