SCNNode Z 旋转轴保持不变,而 X 和 Y 轴在节点旋转时发生变化

SCNNode Z-rotation axis stays constant, while X and Y axes change when node is rotated

我有一个用户可以通过平移手势旋转的节点。用户可以 select X、Y 或 Z 轴和平移,节点将围绕该轴旋转。

问题:节点的正面正对着摄像头。假设用户向右平移并绕 Y 轴旋转节点。节点的正面现在面向右侧。如果用户切换到 X 轴并向下平移,则节点的正面将从其初始的右向方向向下旋转(或从用户的角度顺时针旋转)。这是期望的行为。当用户切换到 Z 旋转时,问题就出现了。如果用户切换到 Z 轴旋转并向右平移,则节点将向下旋转(从用户的角度来看是顺时针方向)。

本质上,节点的 Z 轴始终不变,永远不会偏离其初始方向,但 X 和 Y 轴会发生变化,受其他轴旋转的影响。

谁能解释一下这是什么原因造成的?

下面是我用来旋转节点的代码:

let translation = sender.translation(in: sceneView)
        var newAngleX = Float(translation.y)*Float((Double.pi)/180.0)
        var newAngleY = Float(translation.x)*Float((Double.pi)/180.0)
        var newAngleZ = Float(translation.x)*Float((Double.pi)/180.0)

        if axisSelected == "x" {
            newAngleX += currentAngleX
            node.eulerAngles.x = newAngleX
            if(sender.state == .ended) {
                currentAngleX = newAngleX
            }
        }
        if axisSelected == "y" {
            newAngleY += currentAngleY
            node.eulerAngles.y = newAngleY
            if(sender.state == .ended) {
                currentAngleY = newAngleY
            }
        }
        if axisSelected == "z" {
            newAngleZ += currentAngleZ
            node.eulerAngles.z = newAngleZ
            if(sender.state == .ended) {
                currentAngleZ = newAngleZ
            }
        }

正如我之前在 your post 中所写,这是一个 Gimbal Lock 问题。 Gimbal Lock是三维机构失去一个DoF。 SceneKit中有两个变量:eulerAngles(固有欧拉角,以弧度表示,表示围绕x-y-z轴旋转3圈的序列,顺序如下:Z-Y-X or roll, yaw, pitch) and orientation (node's orientation, expressed as quaternion).

为了摆脱 ARKit 和 SceneKit 中的 gimbal lock 你需要使用单位四元数,其分量满足等式:

(x * x) + (y * y) + (z * z) + (w * w) == 1

要正确应用四元数,您还需要使用此结构的第四个组件 (w)。四元数用 SCNVector4 表示,其中 x-y-z 值是归一化分量,w 字段包含旋转角度,单位为弧度,或扭矩大小,单位为牛顿-米)。

万向节锁定 当轴(三个万向节中的两个)被驱动为平行配置时发生。