我想创建一个增强现实视图,它将指向一个方向的对象。但是,当您面向相机时,CoreLocation标题无法正常工作(当您在一楼时,请指向20层楼的顶部)。
它给出了相反的方向(可能是指向电话顶部的方向)。
我尝试了一些方法让它适用于相机指向的方向,例如:
当设备方向> 1时,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;
我已经不知道还有什么可以尝试让它正确。我知道有一些应用程序(一些可以看到太阳和星星的应用程序)正确地执行它。
答案 0 :(得分:14)
经过大量的研究和测试。我最终使用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;
}
答案 1 :(得分:3)
为了节省其他人的时间,这是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
}