2013-07-29 48 views
4

我想創建一個增強現實視圖,將指向一個方向的對象。但是,當您使用相機朝上時,CoreLocation標題無法正常工作(例如,當您位於底層時,請將其指向20層建築物的頂部)。CoreLocation標題基於背部相機(增強現實)

它給出了相反的方向(可能是電話頂部指向的方向)。

我已經嘗試了一些方法來得到它的相機指向的方向努力,如:

1,+180度當設備方向爲> 45度(不夠準確,突然方向下降10〜20度)

2,試圖用下面的教程中的公式使用CMMotionManager進行計算。 http://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial

3,試圖使用ios deviceMotion.magneticField和deviceMotion.gravity從android模擬邏輯。

4,使用旋轉矩陣(其他一些崗位在堆棧溢出,但不準確)

double heading = M_PI + atan2(self.altitudeData.rotationMatrix.m22, self.altitudeData.rotationMatrix.m12); 
    heading = heading*180/M_PI; 

我跑出來的想法還有什麼我能設法得到它的權利。我知道那裏有一些應用程序(一些可以看到太陽和星星的應用程序),它正確地做到了。

回答

12

經過大量的研究和測試。我最終使用GLKit進行計算,因爲它也爲我節省了很多麻煩。任何碰巧遇到這個問題的人都可以把它留在這裏。

首先,我使用CMAttitudeReferenceFrameXTrueNorthZVertical啓動了CMMotionManager設備運動更新。

self.hasMotion = NO; 
CMMotionManager *cmmotionManager = [[CMMotionManager alloc] init]; 
[cmmotionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical 
                toQueue:[[NSOperationQueue alloc] init] 
               withHandler:^ (CMDeviceMotion *motion, NSError *error) { 
                self.hasMotion = YES; 


               }]; 
self.motionManager = cmmotionManager; 

從一些代碼,我發現在網絡上使用CoreMotion旋轉繪製一個OpenGL世界,並將其與正從屏幕的一個點到3D世界搭配:

float aspect = fabsf(self.view.bounds.size.width/self.view.bounds.size.height); 
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0f), aspect, 0.1f, 100.0f); 

CMRotationMatrix r = self.motionManager.deviceMotion.attitude.rotationMatrix; 
GLKMatrix4 camFromIMU = GLKMatrix4Make(r.m11, r.m12, r.m13, 0, 
             r.m21, r.m22, r.m23, 0, 
             r.m31, r.m32, r.m33, 0, 
             0,  0,  0,  1); 

GLKMatrix4 viewFromCam = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, 0); 
GLKMatrix4 imuFromModel = GLKMatrix4Identity; 
GLKMatrix4 viewModel = GLKMatrix4Multiply(imuFromModel, GLKMatrix4Multiply(camFromIMU, viewFromCam)); 
bool isInvertible; 
GLKMatrix4 modelView = GLKMatrix4Invert(viewModel, &isInvertible); 

int viewport[4]; 
viewport[0] = 0.0f; 
viewport[1] = 0.0f; 
viewport[2] = self.view.frame.size.width; 
viewport[3] = self.view.frame.size.height; 

bool success; 
//assume center of the view 
GLKVector3 vector3 = GLKVector3Make(self.view.frame.size.width/2, self.view.frame.size.height/2, 1.0);  
GLKVector3 calculatedPoint = GLKMathUnproject(vector3, modelView, projectionMatrix, viewport, &success); 
if(success) 
{ 
    //CMAttitudeReferenceFrameXTrueNorthZVertical always point x to true north 
    //with that, -y become east in 3D world 
    float angleInRadian = atan2f(-calculatedPoint.y, calculatedPoint.x); 
    return angleInRadian; 
} 
+0

謝謝user2629068,通過這種方式一切都按預期工作。 – kokemomuke

+0

太棒了!在網絡上有大量的解決方案,試圖解決這個問題,但這是唯一一個工作正常:) –

+0

感謝這個代碼,很好地支持我的相機的輕微運動!不過,我的標題精確度大概是10度。有沒有辦法將這個精度降低到一個更低的值(從而改善標題的正確性)? –

1

爲了節省別人的時間,這裏是Chee在Swift的回答:

import GLKit  

func headingCorrectedForTilt() -> Float?{ 
     guard let motion = self.motionManager.deviceMotion else{ 
      return nil 
     } 

     let aspect = fabsf(Float(self.view.bounds.width/self.view.bounds.height)) 
     let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0), aspect, 0.1, 100) 


     let r = motion.attitude.rotationMatrix 
     let camFromIMU = GLKMatrix4Make(Float(r.m11), Float(r.m12), Float(r.m13), 0, 
          Float(r.m21), Float(r.m22), Float(r.m23), 0, 
          Float(r.m31), Float(r.m32), Float(r.m33), 0, 
          0,  0,  0,  1) 

     let viewFromCam = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, 0); 
     let imuFromModel = GLKMatrix4Identity 
     let viewModel = GLKMatrix4Multiply(imuFromModel, GLKMatrix4Multiply(camFromIMU, viewFromCam)) 
     var isInvertible : Bool = false 
     let modelView = GLKMatrix4Invert(viewModel, &isInvertible); 
     var viewport = [Int32](count:4,repeatedValue: 0) 

     viewport[0] = 0; 
     viewport[1] = 0; 
     viewport[2] = Int32(self.view.frame.size.width); 
     viewport[3] = Int32(self.view.frame.size.height); 

     var success: Bool = false 
     let vector3 = GLKVector3Make(Float(self.view.frame.size.width)/2, Float(self.view.frame.size.height)/2, 1.0) 
     let calculatedPoint = GLKMathUnproject(vector3, modelView, projectionMatrix, &viewport, &success) 

     return success ? atan2f(-calculatedPoint.y, calculatedPoint.x) : nil 
    }