我最近遇到了同样的问题,如何将扭矩从对象的局部空间转换为applyTorque 方法所需的世界空间。使用节点的convertPosition:toNode 和fromNodes 方法的问题在于它们还将节点的平移应用于扭矩,因此这仅在节点位于0,0,0 时有效。这些方法所做的是将 SCNVector3 视为 w 分量为 1.0 的 vec4。我们只想应用旋转,换句话说,我们希望 vec4 的 w 分量为 0。与 SceneKit 不同,GLKit 为我们提供了 2 个选项来说明我们希望 vec3 的倍增方式:
GLKMatrix4MultiplyVector3 在哪里
输入向量被视为 w 分量为 0.0 的 4 分量向量。
和GLKMatrix4MultiplyVector3WithTranslation 在哪里
输入向量被视为 w 分量为 1.0 的 4 分量向量。
这里我们想要的是前者,只是旋转,而不是平移。
所以,我们可以往返 GLKit。例如,要将局部 x 轴 (1,0,0)(例如俯仰旋转)转换为施加扭矩所需的全局轴,如下所示:
let local = GLKMatrix4MultiplyVector3(SCNMatrix4ToGLKMatrix4(node.presentationNode.worldTransform), GLKVector3(v: (1,0,0)))
node.physicsBody?.applyTorque(SCNVector4(local.x, local.y, local.z, 10), impulse: false)
然而,更 Swiftian 的方法是为 mat4 * vec3 添加一个 * 运算符,它将 vec3 视为具有 0.0 w 分量的 vec4。像这样:
func * (left: SCNMatrix4, right: SCNVector3) -> SCNVector3 { //multiply mat4 by vec3 as if w is 0.0
return SCNVector3(
left.m11 * right.x + left.m21 * right.y + left.m31 * right.z,
left.m12 * right.x + left.m22 * right.y + left.m32 * right.z,
left.m13 * right.x + left.m23 * right.y + left.m33 * right.z
)
}
虽然这个操作符假设我们希望我们的 vec3s 如何相乘,但我的推理是,由于 convertPosition 方法已经将 w 视为 1,所以有一个 * 操作符也是多余的这个。
您还可以添加一个 mat4 * SCNVector4 运算符,让用户明确选择他们希望 w 为 0 还是 1。
因此,我们不必从 SceneKit 到 GLKit 往返,只需编写:
let local = node.presentationNode.worldTransform * SCNVector3(1,0,0)
node.physicsBody?.applyTorque(SCNVector4(local.x, local.y, local.z, 10), impulse: false)
您可以使用此方法通过一个applyTorque 调用在多个轴上应用旋转。所以说,如果你有摇杆输入,你希望摇杆上的 x 是偏航(本地 yUp 轴)和摇杆上的 y 是俯仰(本地 x 轴),但具有飞行模拟风格“向下拉回/ up",然后你可以设置为SCNVector3(input.y, -input.x, 0)