如何使用SceneKit实现3D指南针

目前我在制作3D指南针function方面感到困惑。 使用SceneKit,我加载了一个箭头对象,然后像下面的代码一样获取传感器数据(效果就是这个video )

let motionManager = CMMotionManager() motionManager.deviceMotionUpdateInterval = 1.0/60.0 if motionManager.isDeviceMotionAvailable { motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (devMotion, error) -> Void in arrow.orientation = SCNQuaternion(-CGFloat((motionManager.deviceMotion?.attitude.quaternion.x)!), -CGFloat((motionManager.deviceMotion?.attitude.quaternion.y)!), -CGFloat((motionManager.deviceMotion?.attitude.quaternion.z)!), CGFloat((motionManager.deviceMotion?.attitude.quaternion.w)!)) })} 

完成后,如果用户在任何轴上旋转设备,箭头也可以旋转。 由于这是一个3D指南针,我需要箭头指向方向。 所以我通过CLLocationManager获取标题数据,然后问题就来了。

 let gq1: GLKQuaternion = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(heading), 0, 0, 1) arrow.orientation = SCNVector4(gq1.x,gq1.y,gq1.z,gq1.w) 

上面的代码在2D中像下面的图片一样完美,它正确地指向了东方向。 但我想在3D环境中,所以我喜欢下面

 motionManager.deviceMotionUpdateInterval = 1.0/60.0 if motionManager.isDeviceMotionAvailable { motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (devMotion, error) -> Void in arrow.orientation = orient(q: (motionManager.deviceMotion?.attitude.quaternion)!, angle: heading) } func orient(q:CMQuaternion,angle:Float) -> SCNQuaternion{ GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-angle), 0, 0, 1) let gq1: GLKQuaternion = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-angle), 0, 0, 1) // add a rotation in z axis let gq2: GLKQuaternion = GLKQuaternionMake(Float(qx), Float(qy), Float(qz), Float(qw)) // the current orientation let qp: GLKQuaternion = GLKQuaternionMultiply(gq1, gq2) // get the "new" orientation var rq = CMQuaternion() rq.x = Double(qp.x) rq.y = Double(qp.y) rq.z = Double(qp.z) rq.w = Double(qp.w) return SCNVector4(-Float(rq.x), -Float(rq.y), -Float(rq.z), Float(rq.w)) } 

有一个错误( 这个video显示),如果我围绕z轴旋转设备,箭头仍然围绕y轴旋转。 我做错了什么吗?

在这里输入图像说明

如果我用这种方法围绕z轴旋转设备,方向数据会不断出来。 因此,我无法使用CLLocationManager来实现我的目标。 这个线程是我想要的。