如何仅用 4D 矢量表示旋转?

How can I express a rotation with just a 4D vector?

我正在学习如何使用 SceneKit,我对涉及 SCNVector4 的 methods/properties 深感困惑,例如 SCNPhysicsBody.applyTorqueSCNNode.rotation。显然,您可以仅使用 4 个值来表示 3D 对象的旋转。我完全不明白这是为什么。

我在网上搜索 "express 3d rotation with 4d vector",发现很多关于 4D 旋转的东西 space,这不是我想要的。我也看到很多网页都在讲sin和cos,但是没看懂是什么意思。我对 sin 和 cos 的了解仅限于求 angles/side 个直角三角形的长度。

在我看来,3D 对象的旋转需要用 7 个值表示,即 7D 向量:

我认为我对 SpriteKit 中的 2D 旋转理解得很好:每个节点都有一个锚点,因此旋转 属性 就是围绕锚点的弧度。但是,我在SCNNode中找不到这样的锚点。当我查找 "anchor point scnnode" 时,我得到了关于 ARSCNNode 的信息,这不是我想要的。

我也看了this,里面说:

The x-, y- and z-components determine the rotation axis, while the w-component determines the rotation angle, that is, the magnitude of the torque.

如何仅通过 x,y,z 分量指定旋转轴?

你能解释一下我是如何解决这个疯狂问题的吗?

I guess now the question becomes "where on the node is the 'origin'"

由(减去)SCNNode.position (source) 给出。这是相对于其父节点应用于它的翻译。

... and "how do you express 2 angles with 3 scalars" ...

根据Euler's Displacement Theorem任何 3D中的旋转都可以用轴和旋转角度来表示。这些又可以存储为:

  1. 或者(如@OliverCharlesworth建议的)2个指定轴的球形极角和另一个指定旋转角
  2. 或平行于轴的矢量,其大小与围绕它的顺时针(或逆时针)旋转成正比;这是例如通常 angular 速度是如何表示的

SceneKit 仅使用 4D 向量来避免重新计算笛卡尔坐标轴((1) 需要)或检索角度((2))。

In my mind, a rotation of a 3D object needs to be expressed with 7 values i.e. a 7D vector:

  • 3 values for the position of one end of the rotation axis
  • 3 values for the position of the other end of the rotation axis
  • 1 value for the angle you rotate by

问题出在这里:您混淆了单词 "axis" 的两个定义,可以是:

  • space中的固定行,例如X 轴
  • 相互平行的一族线的共同方向

按照惯例,第二个用于指定旋转。这个旋转的中心就是节点的中心位置(通常是它的AABB的中点)。

我意识到我可以写一些 "SceneKit console" 东西来测试向量中四个值中的每一个的作用。

我将一个文本字段、一个按钮和一个 SCNView 放入视图控制器的视图中。在场景中,我添加了一个带有运动物理体的地面节点和一个带有动态物理体的盒子节点。然后我做了这样当点击按钮时,在文本字段中输入的命令将 运行。这就是我解析命令的方式:

func executeCommand(_ command: String) {
    let parts = command.components(separatedBy: " ")
    let node: SCNNode
    guard let nodeString = parts.first else { return }
    switch nodeString {
    case "box": node = box
    case "ground": node = ground
    default: return
    }
    guard let selector = parts.dropFirst().first else { return }
    switch selector {
    case "applyTorque":
        if parts.count == 6 {
            let x = Double(parts[2])!
            let y = Double(parts[3])!
            let z = Double(parts[4])!
            let w = Double(parts[5])!
            let direction = SCNVector4(x, y, z, w)
            node.physicsBody?.applyTorque(direction, asImpulse: true)
        }
    // I decided to add other commands as well, but they're irrelevant so I left them out
    default: break
    }
}

现在,我尝试输入 box applyTorque 1 0 0 1 之类的命令,看看发生了什么。这是我的发现:

  • 前三个值表示节点应分别绕 x、y 和 z 轴旋转多少。
  • 最后一个值似乎是 "overall force"。如果我将其设置为 0,那么无论其他值是什么,盒子都不会移动。
  • 似乎绕 y 轴旋转 "easier"。 Y 值为 1 可以 "spin" 立方体 90 度,但是 X 值为 1 只能将盒子从一侧抬高一点。

截图如下: