美文网首页AR/VR/MR
最新:iOS 集成Unity AR

最新:iOS 集成Unity AR

作者: No_longer_xie | 来源:发表于2018-09-26 17:19 被阅读173次

    最近接到一个需求,要接入AR,给了个Vuforia官网地址,还有AR开发部们同事给的demo(需求以demo为主),就直接开干,查了iOS原生接入Unity的资料,还是遇到了很多问题,在此总结记录一下。

    先看效果: 首页 AR扫描后视频播放

    目录

    配置依赖
    Demo封装
    问题汇总

    配置依赖

    首先,我们拿到的demo结构是这样的:


    demo目录
      1. 将 Classes 和 Libraries 文件夹,以及Framework文件夹中的 Vuforia.framework 拖入工程,按下图方式: 导入Classes,Libraries及Vuforia.framework

        -------------------------------------------------->>>

      1. 将 Data 文件夹拖入工程,按下图方式: 导入Data

        -------------------------------------------------->>>

      1. 结果是这样的(注意文件夹的路径,导入 Header Search Paths按此参照): 拖入后

    注:需将 Data / Raw 文件夹内的Vuforia文件夹按步骤二添加到如下位置,否则会扫描无反应:


    Vuforia

    -------------------------------------------------->>>

    • 4.将 Classes 文件夹 main.mm 内容复制到自己项目(ARTest)中的 main.m 中 ,然后ARTest的 main.m 后缀改为 main.mm,删除 Classes 文件夹中的 main.mm (Move To Trash)有报错先忽略, 代码如下图:
    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    #include "RegisterMonoModules.h"
    #include "RegisterFeatures.h"
    #include <csignal>
    
    static const int constsection = 0;
    
    void UnityInitTrampoline();
    
    const char* AppControllerClassName = "UnityAppController";
    int main(int argc, char * argv[]) {
        
        @autoreleasepool {
            UnityInitStartupTime();
            UnityInitTrampoline();
            
            UnityInitRuntime(argc,argv);
            RegisterMonoModules();
            RegisterFeatures();
            
            std::signal(SIGPIPE, SIG_IGN);
            
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    

    -------------------------------------------------->>>

      1. 在build Setting --> other Link Flags 下做如下修改:
     -weak_framework CoreMotion -weak-lSystem
    
    other Link Flags

    -------------------------------------------------->>>

      1. 在build Setting --> Header Search Paths 下做如下修改:
    "$(SRCROOT)/ARTest/Unity" 
    "$(SRCROOT)/ARTest/Unity/Classes"
    "$(SRCROOT)/ARTest/Unity/Classes/Native"
    "$(SRCROOT)/ARTest/Unity/Libraries"
    "$(SRCROOT)/ARTest/Unity/Libraries/libil2cpp/include"
                      (不同项目需要按照文件在工程中的路径来确定,本次路径参照步骤三图片所示路径)
    
    如图所示: Header Search Paths

    -------------------------------------------------->>>

      1. 在build Setting --> Other C Flags 做如下修改:
    -DINIT_SCRIPTING_BACKEND=1 -fno-strict-overflow -DRUNTIME_IL2CPP=1
    
    如图所示: Other C Flags

    -------------------------------------------------->>>

    • 8.在build Setting --> Precompile Prefix Header做如下修改:如图所示: precompile prefix header
    注:若ARTest项目有pch 文件,需合并pch 文件,将Classes内的prefix.pch 内容全部拷贝到本项目中的pch 中,否则编译会报错,如图: PCH文件合并

    -------------------------------------------------->>>

    • 9.在build Setting 做如下操作: Add-user-defined

      加入如下参数:

    GCC_THUMB_SUPPORT:NO 
    GCC_USE_INDIRECT_FUNCTION_CALLS:NO 
    UNITY_RUNTIME_VERSION:2018.2.3f1  <--这个值可能不一样,根据自己unity-demo来 
    UNITY_SCRIPTING_BACKEND: il2cpp
    
    结果: Add-user-defined
    • 10 build Setting --> bitcode关闭
    • 11 添加依赖库,根据demo 来:


      依赖库,根据demo来

    Demo封装(以上编译成功再做如下操作)

    #import <UIKit/UIKit.h>
    @class DTPUnityController;
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (nonatomic, strong) UIWindow *window;
    @property (nonatomic , strong)UIWindow *unityWindow;
    @property (nonatomic, strong) DTPUnityController *unityController;
    - (void)showUnityWindow;
    - (void)hideUnityWindow;
    
    @end
    

    AppDelegate.mm:

    #import "AppDelegate.h"
    #import "DTPUnityController.h"
    
    @interface AppDelegate ()
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        _unityController = [[DTPUnityController alloc]init];
        return YES;
    }
    
    #pragma mark ---------------unity开启与隐藏
    - (UIWindow *)unityWindow
    {
        if (!_unityWindow) {
            if (!UnityGetMainWindow()) {
                _unityWindow = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
            }else{
                _unityWindow = UnityGetMainWindow();
            }
        }
        return _unityWindow;
    }
    - (void)showUnityWindow
    {
        [self.unityWindow makeKeyAndVisible];
    }
    
    - (void)hideUnityWindow
    {
        [self.window makeKeyAndVisible];
        [self.unityController pauseUnity];
    }
    
    @end
    
    • 2.新建一个类 DTPUnityController 继承自 UnityAppController 以下是 .h 内容:
    #import "UnityAppController.h"
    
    @interface DTPUnityController : UnityAppController
    
    + (instancetype)instance;
    
    - (void)initUnity;
    
    - (void)pauseUnity;
    
    - (void)startUnity1;
    
    - (BOOL)isPaused;
    
    @end
    

    .m 内容:

    #import "DTPUnityController.h"
    
    #import "UnityAppController.h"
    #import "UnityAppController+ViewHandling.h"
    #import "UnityAppController+Rendering.h"
    
    #import "DisplayManager.h"
    #import "UnityView.h"
    
    #include "RegisterMonoModules.h"
    #include "RegisterFeatures.h"
    #include <csignal>
    #import "AppDelegate.h"
    
    @interface DTPUnityController()
    
    @property (nonatomic, assign) BOOL isInitUnity;
    
    @end
    
    @implementation DTPUnityController
    
    + (instancetype)instance {
        AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        return delegate.unityController;
    }
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.isInitUnity = NO;
            // 注册Unity的事件
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
            
        }
        return self;
    }
    
    void UnityInitTrampoline();
    
    - (void)initUnity {
         AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        if (!self.isInitUnity) {
            
            [super applicationDidBecomeActive:[UIApplication sharedApplication]];
            
            UnityInitApplicationNoGraphics([[[NSBundle mainBundle] bundlePath] UTF8String]);
            [self selectRenderingAPI];
            [UnityRenderingView InitializeForAPI: self.renderingAPI];
    
            _window = delegate.unityWindow;
            _unityView      = [self createUnityView];
            
            [DisplayManager Initialize];
            _mainDisplay    = [DisplayManager Instance].mainDisplay;
            [_mainDisplay createWithWindow: _window andView: _unityView];
            
            [self createUI];
            [self preStartUnity];
            self.isInitUnity = YES;
            
            _unityView.back = ^{
                [delegate hideUnityWindow];
            };
    
        }else{
            [self startUnity1];
        }
         [delegate showUnityWindow];
    }
    
    - (void)pauseUnity {
        UnitySendMessage("ARCamera", "Exit", "");  // 调Unity方法 退出模型 (与unity交互)
        UnityPause(1);
    }
    
    - (void)startUnity1 {
        UnityPause(0);
    }
    
    - (BOOL)isPaused {
        if (UnityIsPaused() == 1) {
            return YES;
        }
        else {
            return NO;
        }
    }
    
    -(void)applicationDidFinishLaunching:(UIApplication *)application{
        
    }
    
    - (void)appWillEnterForeground:(NSNotification *)notification {
        [super applicationWillEnterForeground:[UIApplication sharedApplication]];
    }
    
    - (void)appDidBecomeActive:(NSNotification *)notification {
        if (nil == self.unityView) {
            return;
        }
        [super applicationDidBecomeActive:[UIApplication sharedApplication]];
    }
    
    - (void)appWillResignActive:(NSNotification *)notification {
        [super applicationWillResignActive:[UIApplication sharedApplication]];
    }
    
    - (void)appWillTerminate:(NSNotification *)notification {
        [super applicationWillTerminate:[UIApplication sharedApplication]];
    }
    
    - (void)appDidReceiveMemoryWarning:(NSNotification *)notification {
        [super applicationDidReceiveMemoryWarning:[UIApplication sharedApplication]];
    }
    
    
    @end
    
      1. 调整demo代码,扫描页面添加返回按钮callback(UnityView.h):
    点击返回退出的回调

    UnityView.mm 添加返回按钮UI, addBackBtn 方法在initWithFrame中调用:

    - (void)addBackBtn{
        UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        backBtn.frame = CGRectMake(20, 20, 70, 40);
        [self addSubview:backBtn];
        [backBtn setTitle:@"< 返回" forState:UIControlStateNormal];
        [backBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [backBtn addTarget:self action:@selector(touchEvents) forControlEvents:UIControlEventTouchUpInside];
    }
    
    - (void)touchEvents{
        if (self.back) {
            self.back();
        }
    }
    

    ------------------------------------->>

    • 4.在UnityAppController.h 中按如图修改: 修改方法
    • 5.在ViewController中添加开启AR代码:
    - (IBAction)startAR:(id)sender {
        
        DTPUnityController *vc = [DTPUnityController instance];
        [vc initUnity];
    }
    

    以上就是全部过程了。

    问题汇总

      1. 第一次运行demo 扫描后发现可以播放,但没有声音,音量也开到最大,以为是bug,找了好久,后面同事提示是否手机开了静音,煞笔了。。。。
      1. 当配置环境时,出现各种头文件引用报错,看是否引用了C C++代码 是的话看下文件是否.mm 结尾,不是的话要相应做修改 。另外,多数情况是Header Search Paths 路径有误,pch 文件合并,还有frameWork路径带来的报错,当然还有build setting 中的 C Language 设置。
      1. 有些报错还是无法解决,只能重新弄个工程集成了,xcode有时会抽风。
      1. 初始化在main 函数里面进行了,然后没找到返回按钮的退出api,只能暂停,然后调用unity 的移除模型api (若没有需要与unity 工程师沟通)。
      1. 最大的坑就是好不容易集成了,扫描无反应,扫描的图片都是需要在官网先注册的,然后有对应的.dat .xml 文件,扫描不了就是这两个文件路径有问题,具体路径设置代码在哪,还希望广大高手指出,非常感激。
      1. 项目多Target时,Target名不能为中文,否则会 EXC_BAD_ACCESS 闪退,原因尚且不知。

    相关文章

      网友评论

      • 且听风吟SW:弱弱地问一下,AR 集成之后,项目如何瘦身?主要是 AR 资源包太大,八九百兆。上架之后,APP 大小是 140M。请指教!
        且听风吟SW:@No_longer_xie Android 的unity资源包是70多M,iOS 的是700多M,问unity,他也不知道!:joy:
        且听风吟SW:@No_longer_xie 谢谢,我试试!
        No_longer_xie:可以让unity同事帮忙减小下资源包大小, 或者开启bitCode试试(这个报错有时有,有时没有)

      本文标题:最新:iOS 集成Unity AR

      本文链接:https://www.haomeiwen.com/subject/shsdoftx.html