【问题标题】:SCNQuaternion MultiplicationSCN四元数乘法
【发布时间】:2015-02-28 14:09:17
【问题描述】:

我正在尝试使用 Swift 在 SceneKit 中执行 SCNQuaternion 乘法。下面的代码在 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
        ()
    ))

【问题讨论】:

    标签: ios swift f# quaternions scenekit


    【解决方案1】:

    SceneKit 不包含用于进行四元数数学运算的库。 SCNQuaternion 只是 SCNVector4 的类型别名——换句话说,它是一个存放四元数的四个系数的地方,但你需要自己做数学来解释或使用它们。

    在 Xcode 9 / iOS 11 / macOS 10.13 High Sierra / 等中,有一种更好的方法来处理 SceneKit 中的四元数(和其他矢量/矩阵数学):SIMD 库包括两种四元数类型(用于双精度和浮点数), SceneKit 复制所有 SCNVector/SCNMatrix/SCNQuaternion 访问器以提供 SIMD 版本。使用 SIMD 类型而不是 SCN 类型有很多很好的理由:

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

    不幸的是,CoreMotion 还没有(还没有?)为其矢量/矩阵/四元数类型采用 SIMD 库,因此在使用 SIMD 函数或 SceneKit SIMD 之前,您需要将输入的 CMQuaternion 转换为 simd_quatf基于 API。如果您发现自己经常这样做,您可能需要对其进行扩展:

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

    然后(假设我正在阅读您的 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
    }
    

    (*) 一些有用的 SIMD 操作仍然是 C 风格的全局函数:检查 simd/quaternion.h 是否有像 slerp 和 Bézier 插值这样的东西。


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

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

    • Apple 确实在 GLKit 中提供了一个四元数库。使用GLKQuaternionMakeSCNQuaternion 的四个组成部分中创建一个GLKQuaternion。然后你可以乘它,slerp 它,无论使用GLKQuaternion 函数。完成后,使用结果的组件创建另一个SCNQuaternion

    • 在 Swift 1.x (Xcode 6.x) 中,SIMD 库在 Swift 中不可用。 GLKit 数学是一个不错的替代品,但你最好只使用更新的 Xcode - 请记住,即使使用 Swift 4,你也可以一直定位到 iOS 7 / macOS 10.9 Mavericks(并且 SIMD 库早在iOS 8 / macOS 10.10 优胜美地)。

    【讨论】:

    • 在我查看 API 之前,我绝对认为 slerp 是你编造的词。
    猜你喜欢
    • 2017-08-15
    • 2016-12-23
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多