SCNQuaternion乘法

Nic*_* S. 3 f# quaternions ios scenekit swift

我正在尝试使用Swift在SceneKit中执行SCNQuaternion Multiplication.以下代码在F#(Xamarin iOS开发)中.我正在尝试将该代码转换为Swift.

我陷入困境:让dqm = SCNQuaternion.Multiply ... SceneKit没有名为multiply的成员.

知道我怎么能这样做吗?

    let rr = CMAttitudeReferenceFrame.XArbitraryCorrectedZVertical
    this.motion.DeviceMotionUpdateInterval <- float (1.0f / 30.0f)
    this.motion.StartDeviceMotionUpdates (rr,NSOperationQueue.CurrentQueue, (fun d e ->
        let a = this.motion.DeviceMotion.Attitude
        let q = a.Quaternion
        let dq = new SCNQuaternion(float32 q.x, float32 q.y, float32 q.z, float32 q.w)
        let dqm = SCNQuaternion.Multiply (dq, SCNQuaternion.FromAxisAngle(SCNVector3.UnitZ, piover2))
        camNode.Orientation <- dqm
        ()
    ))
Run Code Online (Sandbox Code Playgroud)

ric*_*ter 8

SceneKit不包含用于执行四元数数学的库.SCNQuaternion只是一个类型别名SCNVector4- 换句话说,它是一个容纳四元数的四个系数的地方,但是你可以自己做数学来解释或使用它们.

在Xcode 9/iOS 11/macOS 10.13 High Sierra/etc中,有一种更好的方法来处理SceneKit中的四元数(和其他向量/矩阵数学):SIMD库包括两个四元数类型(用于double和float),以及SceneKit重复所有SCNVector/SCNMatrix/SCNQuaternion访问器都提供SIMD版本.使用SIMD类型而不是SCN类型有很多很好的理由:

  • SIMD类型用于多个iOS/macOS/etc框架,因此您可以使用它们在(例如)SceneKit,ARKit和Model I/O之间传递矢量/矩阵/四元数值,而无需进行转换或转换.
  • Metal shader语言为其矢量/矩阵类型使用相同的库,因此您的数学代码可以在CPU和GPU之间轻松移植.
  • 在Swift中,SIMD类型显示为具有初始化器,属性和方法的结构,因此大多数(*)代码都可以是Swift友好的.
  • 在Swift和C++中,运算符重载涵盖了所有基本操作,因此您的数学代码和读写都像数学一样.
  • 所有上述内容都是使用编译器内在函数实现的,因此它们使用运行代码的CPU的本机向量指令集(x86 SSE,ARM NEON)来快速执行.

不幸的是,CoreMotion还没有采用SIMD库来实现其矢量/矩阵/四元数类型,因此在使用SIMD函数或基于SceneKit SIMD的API之前,您需要将输入转换CMQuaternionsimd_quatf.如果您发现自己经常这样做,您可能需要一个扩展名:

extension simd_quatf {
    init(_ cmq: CMQuaternion) {
        self.init(ix: Float(cmq.x), iy: Float(cmq.y), iz: Float(cmq.z), r: Float(cmq.w))
    }
}
Run Code Online (Sandbox Code Playgroud)

然后(假设我正在阅读你的F#),你的代码在Swift中会变成这样:

let zAxis = float3(x: 0, y: 0, z: 1)
let rotateAroundZ = simd_quatf(angle: .pi/2, axis: zAxis)
manager.startDeviceMotionUpdates(using: .xArbitraryZVertical, to: queue) { motion, error in
    guard let motion = motion else { /* handle error and */ return }

    let deviceQuaternion = simd_quatf(motion.attitude.quaternion)
    cameraNode.simdOrientation = deviceQuaternion * rotateAroundZ
}
Run Code Online (Sandbox Code Playgroud)

(*)一些有用的SIMD操作仍然是C风格的全局函数:检查simd/quaternion.hslerp和Bézier插值等内容.


对于早期的Xcode/SDK版本......

  • 在Xcode 9/iOS 11/macOS 10.13/etc之前,SIMD中没有四元数,而且SceneKit中没有特定于SIMD的访问器.对于除四元数之外的所有内容,获取SCN类型,将它们按组件方式转换为等效的SIMD类型并在那里进行数学运算仍然很有用.

  • Apple确实在GLKit中发布了一个四元数库.使用GLKQuaternionMake做一个GLKQuaternion从你的四个组成部分SCNQuaternion.然后你可以将它乘以它,slerp它,无论使用什么GLKQuaternion函数.完成后,使用结果的组件来制作另一个组件SCNQuaternion.

  • 在Swift 1.x(Xcode 6.x)中,Swift不提供SIMD库.GLKit数学是一个不错的替代品,但你最好只使用更新的Xcode - 记住你可以一直回到iOS 7/macOS 10.9 Mavericks甚至使用Swift 4(并且SIMD库可以追溯到iOS 8/macOS 10.10 Yosemite).