我正在开发一款 SceneKit iOS 游戏,玩家可以在 3D 空间中控制一艘太空飞船。我的最终目标是实现船舶角度稳定,当用户停止提供旋转输入时,船舶将自动停止滚动/俯仰/偏航。例如,如果飞行员使船舶直线水平飞行并进行“桶滚”,当飞行员不再命令滚滚时,我希望船舶自动提供与滚滚相反方向的扭矩,直到船舶不再命令滚滚。更长的任意滚动角速度。
我能够以编程方式识别船舶当前角旋转的最接近方法是获取
ship.physicsBody?.angularVelocity
并将其转换为欧拉角。只要我没有将船从原来的位置/方向移开,我就能得到我期望的结果。然而,一旦我移动船舶,报告的 angleVelocity 值似乎会旋转(例如不再处于“身体固定”坐标系中)。
有没有办法获得局部“身体固定”坐标中的角速度?例如,假设我的船现在“停止”在某个任意位置,并进行任意旋转。现在假设我开始绕其 z 轴滚动飞船(这样飞行员就可以感知到前窗外的环境顺时针旋转)。如何将 ship.physicsBody?.angularVelocity
的输出转换为仅报告滚动轴上的角速度?
angularVelocity
数据相关的有意义的信息。
我过去曾使用过 3d 旋转,但从未使用过四元数。我仍然不太了解四元数,但现在我已经足够了解它们可以用“角轴”表示形式表示,这意味着四元数(0.0, 0.0i, 0.0j, 1.0k)
具有表示为
cos(90) + sin(90)(0.0i + 0.0j + 1.0k)
的角轴表示形式。 Grant Sanderson和 Ben Eater 制作的这个视频系列 非常有帮助。 学习完之后,我注意到SCNPhysicsBody头文件定义了
angularVelocity
,如下:
//Specifies the angular velocity of the receiver as an axis angle.
open var angularVelocity: SCNVector4
我终于意识到这个数据是以角轴格式表示的四元数。
以下是我想出的解决方案。这并不理想,因为我首先将四元数转换为欧拉角,然后旋转欧拉角。我相信更好的解决方案是首先旋转四元数,然后将最终结果转换为欧拉角。不幸的是,据我所知,SceneKit 只提供了
convertVector
和
convertTransform
函数来旋转 SCNVector3
和 SCNMatrix4
数据,但没有提供旋转 SCNQuaternion
的功能。我仍然不太明白这一点,还没有自己手动编写代码来旋转这个四元数。public extension SCNNode {
var localAngularVelocity: SCNVector3 {
let angularVelocity_as_angleAxis = self.physicsBody!.angularVelocity
let simd_angularVelocityQuat = simd_quatf( angle: angularVelocity_as_angleAxis.w,
axis: SIMD3<Float>( x: angularVelocity_as_angleAxis.x,
y: angularVelocity_as_angleAxis.y,
z: angularVelocity_as_angleAxis.z ) )
let n = SCNNode()
n.simdOrientation = simd_angularVelocityQuat
let vectorInWorld = n.eulerAngles
let me = self.presentation
// Rotate vector from world coord system to my local coord system
return me.convertVector(vectorInWorld, from: nil)
}
}