How to implement a 3D compass with SceneKit

被刻印的时光 ゝ 提交于 2019-12-12 03:58:09

问题


Currently I am confused in terms of making a functionality of 3D compass. With SceneKit, I loaded an arrow object and then fetched sensor data like the code below (The effect is this 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)!))

        })}

After done this, if the user rotate the device in any axis, the arrow can be rotated as well. Since this is a 3D compass, I need the arrow to point the direction. So I fetched the heading data via CLLocationManager, and then the problem is coming.

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

The above code is doing perfectly in 2D like the pic below, it points the east direction correctly. But I want it in 3D environment, so I did like below

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(q.x), Float(q.y), Float(q.z), Float(q.w))
    // 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))
}

There is a bug(this video shows), if I rotate the device around z axis, the arrow still rotates around y axis. Did I do anything wrong?


回答1:


If I rotate the device around z axis by this method, the direction data comes out continuously. As a result, I can't use CLLocationManager to achieve my goal. This thread is what I want.



来源:https://stackoverflow.com/questions/42363644/how-to-implement-a-3d-compass-with-scenekit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!