CoreLocation标题背后的相机(增强现实)

我想创build一个增强现实视图,它将指向一个方向的对象。 但是,当您使用相机向上时,CoreLocation标题不能正常工作(例如,当您位于底层时,请到20层build筑的顶部)。

这是相反的方向(可能是指向电话顶部的方向)。

我已经尝试了几种方法来使它在相机指向的方向上工作,例如:

1,设备方向> 45度时+180度(不够精确,突然方向10-20度)

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

3,试图使用ios deviceMotion.magneticField和deviceMotion.gravity从android模拟逻辑。

4,使用旋转matrix(其他一些post在堆栈溢出,但不准确)

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

我正在想出我还有什么可以尝试做到的。 我知道那里有一些应用程序(一些可以看到太阳和星星的应用程序),这是正确的。

经过大量的研究和testing。 我最终使用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; 

从我在网上find的一些代码中,使用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; } 

为了节省其他人的时间,这是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 }