Reputation: 3303
I'm trying to perform a SCNQuaternion Multiplication in SceneKit with Swift. The code below is in F# (Xamarin iOS Development). I'm trying to translate that code into Swift.
I'm stuck at the line: let dqm = SCNQuaternion.Multiply... SceneKit doesn't have a member called multiply.
Any idea how I can do this?
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
()
))
Upvotes: 4
Views: 4739
Reputation: 126157
SceneKit doesn't include a library for doing quaternion math. SCNQuaternion
is just a type alias for SCNVector4
— in other words, it's a place to hold the four coefficients of a quaternion, but you're left to do your own math to interpret or work with them.
In Xcode 9 / iOS 11 / macOS 10.13 High Sierra / etc, there's a better way to deal with quaternions (and other vector/matrix math) in SceneKit: the SIMD library includes two quaternion types (for double and float), and SceneKit duplicates all the SCNVector/SCNMatrix/SCNQuaternion accessors to provide SIMD versions. There's lots of great reasons to use SIMD types instead of the SCN ones:
Unfortunately, CoreMotion hasn't (yet?) adopted the SIMD library for its vector/matrix/quaternion types, so you'll need to convert your input CMQuaternion
to simd_quatf
before working with SIMD functions or SceneKit SIMD-based API. If you find yourself doing that often, you might want an extension for it:
extension simd_quatf {
init(_ cmq: CMQuaternion) {
self.init(ix: Float(cmq.x), iy: Float(cmq.y), iz: Float(cmq.z), r: Float(cmq.w))
}
}
Then (assuming I'm reading your F# right), your code becomes something like this in 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
}
(*) Some of the useful SIMD operations are still C-style global functions: Check
simd/quaternion.h
for stuff like slerp and Bézier interpolation.
For earlier Xcode / SDK releases...
Prior to Xcode 9 /iOS 11 / macOS 10.13 / etc, there's no quaternions in SIMD, and no SIMD—specific accessors in SceneKit. For everything but quaternions, it can still be useful to take the SCN types, convert them component-wise to the equivalent SIMD types, and do your math there.
Apple does ship a quaternion library in GLKit. Use GLKQuaternionMake
to make a GLKQuaternion
from the four components of your SCNQuaternion
. Then you can multiply it, slerp it, whatever using GLKQuaternion
functions. When done, use the components of the result to make another SCNQuaternion
.
In Swift 1.x (Xcode 6.x), the SIMD library isn't available from Swift. GLKit math is a halfway decent substitute, but you're better off just using a newer Xcode — remember you can target all the way back to iOS 7 / macOS 10.9 Mavericks even with Swift 4 (and the SIMD library is available as far back as iOS 8 / macOS 10.10 Yosemite).
Upvotes: 10