ios - 如何让手机进入增强现实 (iOS)

标签 ios iphone objective-c augmented-reality

我是一个 非常 的 iOS 和 android 开发新手,我必须开发一个增强现实应用程序(基于位置),并且在使用 获得好的结果时遇到了麻烦>指南针

已经制作 android 上的应用程序,解决方案只是使用来自加速度计和磁场的RollYaw 数据,如下图所示: http://en.wikipedia.org/wiki/Flight_dynamics 并像 android 文档解释的那样重新映射它们。 (还要感谢 Hoan Nguyen,他帮助我在 Android 上更正了我的代码(感兴趣的人:How to get phone heading for augmented reality? :))


问题是:我无法阻止 trueHeading 受到 roll

的影响

这是我的代码,我尝试使用 NSObject(不确定这是否是一个好的解决方案,如果不是,我将不胜感激一个链接,它能很好地解释我需要什么!:$)

指南针.h

//
//  Compass.h
//  AugmentedReality
//
//  Created by Dany Humbert on 20/02/2014.
//  Copyright (c) 2014 Dany Humbert. All rights reserved.
//

#include <CoreMotion/CoreMotion.h>
#import <CoreFoundation/CoreFoundation.h>
#import <GLKit/GLKit.h>
#import "constants.h"

@interface Compass : NSObject

+ (id) getSingleton:(UIView*)view;

- (double) getHeading;

@end

指南针.m

//
//  Compass.m
//  AugmentedReality
//
//  Created by Dany Humbert on 20/02/2014.
//  Copyright (c) 2014 Dany Humbert. All rights reserved.
//

#import "Compass.h"

@implementation Compass

CMAttitude *attitude;
CMQuaternion quaternion;
CMRotationMatrix rotationMatrix;
double yaw;
double pitch;
double roll;
double gyro_x;
double gyro_y;
double gyro_z;
double acc_x;
double acc_y;
double acc_z;

float updateSpeed;
UIView *userview;
CADisplayLink *motionDisplayLink;
CMMotionManager *motionManager;

/**
 @author Dany
 @date 20 fev 2014
 @brief Singleton for Compass class
 **/
+ (id) getSingleton:(UIView *)view
{
    userview = view;
    static Compass *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

/**
 @author Dany
 @date 21 fev 2014
 @brief init method for compass class
 **/
-(id) init
{
    if((self=[super init])) {

        updateSpeed = 1.0/60.0;
        motionManager = [[CMMotionManager alloc] init];
        motionManager.deviceMotionUpdateInterval = updateSpeed;
        motionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(motionRefresh:)];
        [motionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        if ([motionManager isGyroAvailable]) {
            [motionManager startGyroUpdates];
            [motionManager startDeviceMotionUpdates];
            [motionManager startMagnetometerUpdates];
        }
    }
    return self;
}

/**
 @author Dany
 @date 21 fev 2014
 @brief Refresh all values from sensors
 **/
-(void)motionRefresh:(id)sender
{
    attitude = motionManager.deviceMotion.attitude;
    rotationMatrix = motionManager.deviceMotion.attitude.rotationMatrix;
    quaternion = motionManager.deviceMotion.attitude.quaternion;
    yaw =     IN_DEGREES(motionManager.deviceMotion.attitude.yaw);
    roll =    IN_DEGREES(motionManager.deviceMotion.attitude.roll);
    pitch =   IN_DEGREES(motionManager.deviceMotion.attitude.pitch);
    gyro_x =  IN_DEGREES(motionManager.gyroData.rotationRate.x);
    gyro_y =  IN_DEGREES(motionManager.gyroData.rotationRate.y);
    gyro_z =  IN_DEGREES(motionManager.gyroData.rotationRate.z);
    acc_x =   IN_DEGREES(motionManager.accelerometerData.acceleration.x);
    acc_y =   IN_DEGREES(motionManager.accelerometerData.acceleration.y);
    acc_z =   IN_DEGREES(motionManager.accelerometerData.acceleration.z);
}

#pragma mark -
#pragma Getters Sensors Values
/**
 @author Dany
 @date 21 fev 2014
 @brief return current heading relative to sensors values
 **/
- (double) getHeading
{

    double heading = 0.0;

    /**
     //  @remarks FROM http://www.dulaccc.me/2013/03/computing-the-ios-device-tilt.html || Wrong values returned

     heading = asin(2*(currentSensorState.quaternion.x*currentSensorState.quaternion.z - currentSensorState.quaternion.w*currentSensorState.quaternion.y));
     heading = RAD2DEG * yaw;

     **/

    /**
     //  @remarks FROM https://stackoverflow.com/questions/9341223/how-can-i-get-the-heading-of-the-device-with-cmdevicemotion-in-ios-5 || Wrong values returned

     heading = M_PI + atan2(currentSensorState.rotationMatrix.m22, currentSensorState.rotationMatrix.m12);
     heading = heading*RAD2DEG;

     **/

    /**
     //  @remarks FROM https://stackoverflow.com/questions/17917016/corelocation-heading-base-on-back-camera-augmented-reality || Wrong values returned

     float aspect = fabsf(userview.bounds.size.width / userview.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] = userview.frame.size.width;
     viewport[3] = userview.frame.size.height;

     bool success;
     //assume center of the view
     GLKVector3 vector3 = GLKVector3Make(userview.frame.size.width/2, userview.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);
     heading = angleInRadian*RAD2DEG;
     }

     **/

    /**
     // @remarks FROM https://stackoverflow.com/questions/10692344/cmdevicemotion-yaw-values-unstable-when-iphone-is-vertical || Wrong values returned

     float yawDegrees = currentSensorState.yaw;
     float rollDegrees = currentSensorState;

     double rotationDegrees;
     if(rollDegrees < 0 && yawDegrees < 0) // This is the condition where simply
     // summing yawDegrees with rollDegrees
     // wouldn't work.
     // Suppose yaw = -177 and pitch = -165.
     // rotationDegrees would then be -342,
     // making your rotation angle jump all
     // the way around the circle.
     {
     rotationDegrees = 360 - (-1 * (yawDegrees + rollDegrees));
     }
     else
     {
     rotationDegrees = yawDegrees + rollDegrees;
     }
     heading = rotationDegrees;

     // Use rotationDegrees with range 0 - 360 to do whatever you want.
     **/

    /**
     //  @remarks FROM http://www.raywenderlich.com/3997/augmented-reality-tutorial-for-ios || Wrong values returned

     // Convert the radians yaw value to degrees then round up/down
     float yaw = roundf((float)(currentSensorState.yaw));

     // Convert the yaw value to a value in the range of 0 to 360
     int heading = yaw;
     if (heading < 0) {
     heading += 360;
     }

     **/

    /**
     //  @remarks Personnal test from android development experience

     heading = yaw - roll;
     // TODO : use rotation matrix to handle phone position

     **/

    return heading;
}

@end

如你所见,我尝试了一些基于网络的提议(我在代码部分提供了源代码) 但是所有这些方法都返回了错误的结果...... 我也尝试阅读苹果的官方文档,但就像我说的那样,我很难理解所有内容,而且我无法获得一些真实的例子(女巫在 iOS6 中没有被弃用)......

我是法国人,我很难理解所有答案,所以我很确定我漏掉了一些东西,但我不知 Prop 体在哪里。


顺便说一下,如果它很重要,我的应用程序目标是 6.0+ - 仅限 iPhone。 (决定暂时让出 3% 的 App Store:developer.apple.com/support/appstore/) 我计划做这样的事情:(在 android 上完美工作) animated ruler showing current degree


更新 1

我试图查看 www.metaio.com/sdk 但我没有在这里找到任何教程,这不是我寻找的那种增强现实;无论如何,感谢您的回答 Mehul Thakkar!

更新2

经过一些实验,并尝试计算网络上的一些信息后,我有了一个解决方案的开始。我使用的所有内容都在我链接的代码中,如果您有兴趣,请附上源代码! ;) 好的,这就是我要做的:

// 1. After implementing locationListner i take magnetic and true heading
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    globalHeading = newHeading;
}

// 2. In a function called 'x time second', i get my heading for AR by :
- (void) updateCompassValues
{
       // 2.1 Get Tilt Compensation
    double tiltCompensation = IN_DEGREES(asin(2*(quaternion.x*quaternion.z - quaternion.w*quaternion.y)));

    // 2.2 I transform magneticHeading with this tilt compensation
    currentHeading = globalHeading.magneticHeading + tiltCompensation;
}

值仍然有点不准确,有时航向会跳跃 10°,但我会尝试修复它并尽快更新这篇文章!

最佳答案

好的,所以我解决了我的问题,我停止使用 locationManager,并且我做了一些受 CoreLocation heading base on back camera (Augmented reality) 启发的事情.它处理倾斜和我的 AR 应用程序所需的一切,但需要更多的 CPU 容量。 (没什么大不了的!) 所以谢谢user2629068 !

关于ios - 如何让手机进入增强现实 (iOS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21940015/

相关文章:

objective-c - 从 NSTableView 拖放到 Finder 时出现问题

ios - TAniIndicator 在执行操作时没有动画。

iphone - 在内存占用较小的 iPhone 上调整 UIImage 的大小

ios - Objective-C:从可空指针 'NSURL * _Nullable' 到不可空指针类型 'NSURL * _Nonnull'

iphone - 是否可以在iPhone仿真器上下载并运行iPhone应用程序?

ios - 已发送的消息在 JSQMessageViewController 中添加了两次

iphone - 什么样的下载代码违反了 App Store Review Guideline?

ios - 设置 Collection View 单元格的动态宽度和高度

ios - ObjC class_addMethod 不检查参数类型?

iOS UIScrollView动画后动画