基于ARKit的开发

ARKit是苹果在WWDC2017推出的一个用于实现增强现实(AR)的框架;开发者能够使用它来快速的完成基本的AR功能开发。

软硬件支持范围

  • 硬件:A9处理器及以上(iPhone 6s)
  • 软件:Xcode 9.0、iOS 11 及以上

必须同时具备上述条件。

需要其他什么

  • 相应的3D模型(dae格式)
  • SceneKit、SpriteKit或Metal相关基础知识(用做渲染)

ARKit的类结构图

查看大图

ARKit类结构图

ARKit如何工作

假设,我们需要实现的AR功能是:通过app在现实世界的桌子上放置一个杯子。我们需要通过怎么的步骤来实现这个功能呢?或者说ARKit是怎么实现这样的功能的呢?

AR放置的杯子

总结来说有三个重要的部分:

  • 1、Tracking(实时捕捉周围的信息,并处理生成相应格式的数据)
  • 2、Scene Understanding(理解当前的场景,并找到合适的放置虚拟模型的位置)
  • 3、Rendering(渲染并展示)
Tracking

Tracking是ARKit的核心功能,它负责实时追踪设备。

特性:

  • World tracking(通过World tracking能够得到设备在现实世界的相对位置。)
  • Visual inertial odometry(同时使用摄像机捕捉的图像和设备运动状态来得到一个精确的设备位置和方向)
  • No external setup(无需外部的设置)

ARCamera中有两个属性trackingStatetrackingStateReason,开发者可以根据这两个属性的值,对用户进行相应的提示。

Scene Understanding

Scene Understanding就是理解设备周围环境的特征;例如平面检测,平面检测就是检测并分析出设备周围环境中的平面。

特性:

  • Plane detection(平面检测)
  • Hit-testing(用于寻找现实世界的点)
  • Light estimation(根据现实世界的环境来改变虚拟模型光照)
Rendering

渲染。

特性:

  • Easy integration(集成简单)
  • AR views(实现了大部分的渲染工作)
  • Custom rendering(可以自定义渲染)

ARKit的使用

ARKit是基于会话(ARSession)的一套API,ARSession处理包含Tracking、Scene Understanding以及渲染时需要的数据在内的许多复杂的进程。

ARSession和ARConfiguration

ARSession内部使用了AVCaptureSession和CMMotionManager来获取图像信息和设备运动信息;根据ARConfiguration指定的Tracking类型来合成数据,最终输出ARFrame。每个ARFame包含了渲染需要的所有信息,可以把它理解成对应时间的快照。想要获得ARFrame有两种方式:

  • 1、通过ARSession的委托,在每一帧更新时处理:- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame;
  • 2、通过currentFrame属性,在需要时主动获取当前帧:@property (nonatomic, copy, nullable, readonly) ARFrame *currentFrame;

ARConfiguration决定了Tracking类型;基类ARConfiguration有三个维度的追踪,也即是设备的方向;子类ARWorldTrackingConfiguration拥有6个维度的追踪,它即包含了设备的方向,也包含了设备在现实世界中的相对位置。

可以使用ARConfiguration的类属性isSupported来判断,当前设备是否支持该模式的追踪。@property(class, nonatomic, readonly) BOOL isSupported;

基本使用流程

想要使用ARKit,首要的步骤就是创建ARSession;其次,选用相应的ARConfiguration来决定Tracking的类型;然后使会话运行;之后的操作就是放置虚拟模型并渲染显示。总结如下:

  • 1、创建ARSession对象
  • 2、创建相应的ARConfiguration对象
  • 3、Run Session
  • 4、对场景做相应的检测,找到防止虚拟模型的合适位置
  • 5、添加模型
  • 6、渲染显示

上文中说到SceneKitSpriteKit,在ARKit中,有两个类:ARSCNViewARSKView是分别继承自上述框架中的SCNViewSKView;ARKit结合这两个框架为开发者提供了更加简单的使用过程,可以将ARSCNView(3D)、ARSKView(2D)理解成两种渲染引擎(一个负责3D、一个负责2D),只要开发者选用其中的一种,那么将追踪得到的帧数据就会自动渲染并显示到相应的View上;对于特殊需求,也可以使用Metal来完成自定义的渲染。本文中都是使用ARSCNView来显示场景的。

ARkit以及SceneKit的类关系图(图片摘取于:u013263917博客)

ARkit以及SCeneKit的类关系图

使用ARSCNView时启动Tracking的代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 设置view
    self.sceneView.delegate = self;
    self.sceneView.automaticallyUpdatesLighting = NO;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    if (ARWorldTrackingConfiguration.isSupported) {
        // 防止熄屏
        [UIApplication sharedApplication].idleTimerDisabled = YES;
        
        // 创建一个能够检测水平面的configuration
        ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
        configuration.planeDetection = ARPlaneDetectionHorizontal;
    
        // 运行
        [self.sceneView.session runWithConfiguration:configuration options:ARSessionRunOptionResetTracking|ARSessionRunOptionRemoveExistingAnchors];
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    // 暂停session
    [self.sceneView.session pause];
}

在完成上述的代码之后,就能够在ARSCNView上看到摄像机捕捉的景象。接下来就是找到合适的位置来放置虚拟的模型,如找一个平面,或者一个点。

对于平面,可以使用ARWorldTrackingConfiguration的属性planeDetection来设置(目前只支持水平面),在检测到平面之后,ARKit会自动向Session中添加一个ARAnchorARAnchor代表现实世界中的一个位置,每一个添加到Session中的ARAnchor都会有一个与之对应的节点(SCNNode),于是我们就可以在这个节点上添加模型(子节点)。

如果想要将模型添加到指定的空间点,ARKit为ARFrame提供了Hit-testing。方法声明为:

- (NSArray<ARHitTestResult *> *)hitTest:(CGPoint)point types:(ARHitTestResultType)types;

Hit-testing就是从手机模拟发射一条射线去,寻找与现实世界的交点。

Hit-testing

其中point参数,为当前追踪的图片的相对位置,左上角是(0,0)右下角是(1,1);这个参数可以使用手势来输入。ARHitTestResultType是一个枚举,决定用什么样的方式去Hit-testing

typedef NS_OPTIONS(NSUInteger, ARHitTestResultType) {
    /** 返回射线上与特征点最接近的点 */
    ARHitTestResultTypeFeaturePoint              = (1 << 0),
    
    /** 从当前帧中确定一个平面,然后返回与平面的交点 */
    ARHitTestResultTypeEstimatedHorizontalPlane  = (1 << 1),
    
    /** 将当前已经检测到的平面看作无限大的平面,然后返回与这些平面的交点 */
    ARHitTestResultTypeExistingPlane             = (1 << 3),
    
    /** 仅仅返回当前平面范围内的交点 */
    ARHitTestResultTypeExistingPlaneUsingExtent  = (1 << 4),
} NS_SWIFT_NAME(ARHitTestResult.ResultType);

代码中结合手势使用Hit-testing

- (IBAction)tapAction:(UITapGestureRecognizer *)sender {
    
    // 获取当前帧
    ARFrame *frame = self.sceneView.session.currentFrame;
    if (frame) {
        // 根据手势设置点的位置
        CGPoint location = [sender locationInView:self.sceneView];
        CGSize size = self.sceneView.bounds.size;
        CGFloat x,y;
        
        x = location.x/size.width;
        y = location.y/size.height;
        
        // hit-testing
        NSArray<ARHitTestResult *> * results = [frame hitTest:CGPointMake(x, y) types:ARHitTestResultTypeEstimatedHorizontalPlane];
        if (results.count > 0) {
            // 将得到的第一个点添加到session
            ARHitTestResult *res = [results firstObject];
            ARAnchor *anchor = [[ARAnchor alloc] initWithTransform:res.worldTransform];
            [self.sceneView.session addAnchor:anchor];
        }
    }
}

添加hit-testing的Anchor后,可以在对应的委托方法中,添加相应的虚拟物体的模型

- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
        // 加载模型
        SCNScene *candle = [SCNScene sceneNamed:@"candle.scn" inDirectory:@"Models.scnassets/candle" options:nil];
        SCNNode *candleNode = [[candle.rootNode childNodes] firstObject];
        
        // 添加到对应的节点上
        [node addChildNode:candleNode];
}

效果图如下:

蜡烛

至此已经完成了一个基本的AR应用,如果需要完成更加复杂的应用,还需要掌握很多关于SceneKit的知识(如模型的动画、坐标系的转换等)以及加入更复杂的逻辑和算法。

如何向一个工程中引入ARKit

  • 1、创建一个自定义个ViewController,并为其加上一个ARSCNView,将这个view设置为ViewController的一个属性
step1.png
  • 2、初始化session和configuration
step2.png
  • 3、加载虚拟模型及其他操作

模型的导入

  • 1、创建一个文件夹,用"xxx.scnassets"的方式命名;
import1.png
  • 2、将该文件夹拖入工程;
import2.png
  • 3、将.dae格式的模型拖入该文件夹(在工程中拖入),然后选中Edit菜单,将其转换成scn文件;
import3.png

转换后的结果:


import4.png
  • 4、加载文件,获取需要的节点。
    // 加载场景
    SCNScene *scene = [SCNScene sceneNamed:@"chameleon.scn" inDirectory:@"Models.scnassets" options:nil];
    
    // 获取子节点
    NSArray *childNodes = [scene.rootNode childNodes];

参考资料以及Demo地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,547评论 4 374
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,787评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,175评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,752评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,169评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,056评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,195评论 2 321
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,980评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,724评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,872评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,344评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,667评论 3 264
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,379评论 3 245
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,202评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,992评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,189评论 2 286
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,987评论 2 279