iOS增强现实(ARKit)简单介绍

简介

增强现实技术(<code style='color:red'>Augmented Reality</code>,简称 AR ),是一种实时地计算摄影机影像的位置及角度并加上相应图像、视频、3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动。

Logo.png

概述

  1. ARKit是2017年6月6日,苹果发布iOS11系统所新增框架,它能够帮助我们以最简单快捷的方式实现AR技术功能。
  2. ARKit框架提供了两种AR技术:
1. 基于3D场景(SceneKit)实现的增强现实,
2. 基于2D场景(SprikeKit)实现的增强现实.
  1. AR效果必须要依赖于苹果的游戏引擎框架(3D引擎SceneKit,2D引擎SprikeKit),主要原因是游戏引擎才可以加载物体模型。
  2. 虽然ARKit框架中视图对象继承于UIView,但是由于目前ARKit框架本身只包含相机追踪,不能直接加载物体模型,所以只能依赖于游戏引擎加载ARKit

注意⚠️

Xcode版本:Xcode9及以上,iOS系统:iOS11及以上,iOS设备要求:处理器A9及以上(iPhone6s 、iPhone6sPlus、iPhone7 iPhone7Plus、iPhoneSE、iPad Pro(9.7、10.5、12.9)、iPad(2017))

ARKit主要由三部分组成:

thirdpart.jpeg

1. 跟踪(Tracking)

跟踪是ARKit的核心组件之一,其提供了设备在物理世界中的位置与方向信息,并对物体进行跟踪,如人脸。

2. 场景理解(Scene Understanding)

场景理解通过学习更多关于环境的属性,以对水平平面进行检测,如地面或桌面;iOS 11.3开始还支持检测垂直平面。这些在场景中平面可用于放置虚拟物体。此外,场景理解还会了解当前环境的光照情况,以提供光照信息用于在虚拟场景中反映真实环境,避免过亮或过暗。

3. 渲染(Rendering)

通过ARKit可以很容易地集成你所选的渲染引擎。ARKit可通过SceneKit和SpriteKit渲染。Xcode中还提供了Metal模板,方便快速地开始你的增强现实体验(augmented reality experience)项目。此外,Unity和Unreal也已经集成ARKit完整的功能集到他们主流的游戏引擎中,因此你可以通过这些引擎开始使用ARKit。


ARKit与SceneKit的关系

AR技术叫做 虚拟增强现实技术,也就是在相机捕捉到的现实世界的图像中显示一个虚拟的 3D 模型。
这一过程可以分为两个步骤:

  1. 相机捕捉现实世界图像由 ARKit 来实现
  1. 在图像中显示虚拟 3D 模型 由 SceneKit 来实现

下图是一个ARKit 与 SceneKit 框架的关系图,通过下图可以看出:


ARKit与SceneKit的关系.png
  • 继承:子类拥有父类所有的属性及方法

  • 1 <ARKit>框架中中显示3D虚拟增强现实的视图ARSCNView继承于<SceneKit>框架中的SCNView,而SCNView又继承于<UIKit>框架中的UIView

    UIView的作用是将视图显示在iOS设备的window中,SCNView的作用是显示一个3D场景,ARScnView的作用也是显示一个3D场景,只不过这个3D场景是由摄像头捕捉到的现实世界图像构成的

  • 2 ARSCNView只是一个视图容器,它的作用是管理一个ARSession

  • 3 在一个完整的虚拟增强现实体验中,<ARKit>框架只负责将真实世界画面转变为一个3D场景,这一个转变的过程主要分为两个环节:由ARCamera负责捕捉摄像头画面,由ARSession负责搭建3D场景

  • 4 在一个完整的虚拟增强现实体验中,将虚拟物体显示在3D场景中是由<SceneKit>框架来完成:每一个虚拟的物体都是一个节点SCNNode,每一个节点构成了一个场景SCNScene,无数个场景构成了3D世界

  • 5 综上所述,ARKit捕捉3D现实世界使用的是自身的功能,这个功能是在iOS11新增的。而ARKit在3D现实场景中添加虚拟物体使用的是父类SCNView的功能,这个功能早在iOS8时就已经添加(SceneKit是iOS8新增)


ARKit工作原理

- ARSCNView 与 ARCamera

ARSCNViewARCamera两者之间并没有直接的关系,它们之间是通过AR会话,也就是ARKit框架中非常重量级的一个类ARSession来搭建沟通桥梁的

在iOS框架中,凡是带session或者context后缀的,这种类一般自己不干活,作用一般都是两个:

1.管理其他类,帮助他们搭建沟通桥梁,好处就是解耦
2.负责帮助我们管理复杂环境下的内存

context与session不同之处是:一般与硬件打交道,例如摄像头捕捉ARSession,网卡的调用NSURLSession等使用的都是session后缀。没有硬件参与,一般用context,如绘图上下文,自定义转场上下文等

要想运行一个ARSession会话,你必须要指定一个称之为会话追踪配置的对象:ARSessionConfiguration,ARSessionConfiguration的主要目的就是负责追踪相机在3D世界中的位置以及一些特征场景的捕捉(例如平面捕捉),这个类本身比较简单却作用巨大

ARSessionConfiguration是一个父类,为了更好的看到增强现实的效果,苹果官方建议我们使用它的子类ARWorldTrackingSessionConfiguration,该类只支持A9芯片之后的机型,也就是iPhone6s之后的机型

- ARWorldTrackingConfiguration 与 ARframe

ARWorldTrackingConfiguration(会话追踪配置)的作用是跟踪设备的方向和位置,以及检测设备摄像头看到的现实世界的表面。
它的内部实现了一系列非常庞大的算法计算以及调用了你的 iPhone 必要的传感器来检测手机的移动及旋转甚至是翻滚。

ARWorldTrackingConfiguration 计算出相机在 3D 世界中的位置时,它本身并不持有这个位置数据,而是将其计算出的位置数据交给 ARSession 去管理,而相机的位置数据对应的类就是 ARFrameARSession 类有一个属性叫做 currentFrame ,维护的就是 ARFrame 这个对象。

ARCamera只负责捕捉图像,不参与数据的处理。它属于3D场景中的一个环节,每一个3D Scene都会有一个Camera,它决定了我们看物体的视野
他们三者之间的关系看起来如下图:

三角关系.png

ARCamera 在 3D 世界的位置看起来是这样的:

坐标系.png

默认情况下,每一次 ARSession 在启动时,摄像头的位置就是 3D 世界的原点,而且这个原点不再随着摄像头的移动而改变,是第一次就永久固定的。


ARKit工作完整流程

首先,ARKit 利用摄像头拍摄现实场景的画面,然后 SceneKit 用来建立虚拟世界。
建立好了以后,ARKit 负责将现实世界和虚拟世界的信息融合,并渲染出一个 AR 世界。

在渲染的同时,ARKit 要负责以下三件事:

  1. 维持世界追踪 指的是当你移动摄像头,要去获取新的现实世界的信息。
  2. 进行场景解析 指的是解析现实世界中有无特征点、平面等关键信息。
  3. 处理与虚拟世界的互动 指的是当用户点击或拖动屏幕时,处理有没有点击到虚拟物体或者要不要进行添加/删除物体的操作。

由此可见,ARKit 主要做的事是:捕捉现实世界信息、将现实和虚拟世界混合渲染、并且时刻处理新的信息或者进行互动。


AR工作流程.png
  1. ARSCNView 加载场景 SCNScene
  2. SCNScene 启动相机 ARCamera 开始捕捉场景
  3. 捕捉场景后 ARSCNView 开始将场景数据交给 Session
  4. Session 通过管理 ARSessionConfiguration 实现场景的追踪并且返回一个 ARFrame
  5. 给 ARSCNView 的 scene 添加一个子节点( 3D 物体模型)
  • ARSessionConfiguration捕捉相机3D位置的意义就在于能够在添加3D物体模型的时候计算出3D物体模型相对于相机的真实的矩阵位置
  • 在3D坐标系统中,有一个世界坐标系和一个本地坐标系。类似于UIView的Frame和Bounds的区别,这种坐标之间的转换可以说是ARKit中最难的部分

AR初体验之3D效果

  1. 打开 Xcode ,新建一个工程,选择 Augmented Reality APP (Xcode 9 新增),点击 Next。
  2. 在包含技术选项中选择 SceneKit。
  3. 此时,Xcode 会自动为我们生成一段极其简洁的 AR 代码。
#import "ViewController.h"

@interface ViewController () <ARSCNViewDelegate>

@property (nonatomic, strong) IBOutlet ARSCNView *sceneView;

@end

    
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Set the view's delegate
    //设置代理
    self.sceneView.delegate = self;
    
    // Show statistics such as fps and timing information
    // ARKit统计信息
    self.sceneView.showsStatistics = YES;
    
    // Create a new scene
    // 使用模型创建节点(scn格式文件是一个基于3D建模的文件,使用3DMax软件可以创建,这里系统有一个默认的3D飞机)
    SCNScene *scene = [SCNScene sceneNamed:@"art.scnassets/ship.scn"];
    
    // Set the scene to the view
    // 设置ARKit的场景为SceneKit的当前场景(SCNScene是Scenekit中的场景,类似于UIView)
    self.sceneView.scene = scene;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    // Create a session configuration
    // 创建一个追踪设备配置(ARWorldTrackingSessionConfiguration主要负责传感器追踪手机的移动和旋转)
    ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];

    // Run the view's session
    // 开始启动ARSession会话(启动AR)
    [self.sceneView.session runWithConfiguration:configuration];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    // Pause the view's session
    // 暂停ARsession会话
    [self.sceneView.session pause];
}

#pragma mark - ARSCNViewDelegate

/*
// Override to create and configure nodes for anchors added to the view's session.
- (SCNNode *)renderer:(id<SCNSceneRenderer>)renderer nodeForAnchor:(ARAnchor *)anchor {
    SCNNode *node = [SCNNode new];
 
    // Add geometry to the node...
 
    return node;
}
*/

- (void)session:(ARSession *)session didFailWithError:(NSError *)error {
    // Present an error message to the user
    
}

- (void)sessionWasInterrupted:(ARSession *)session {
    // Inform the user that the session has been interrupted, for example, by presenting an overlay
    
}

- (void)sessionInterruptionEnded:(ARSession *)session {
    // Reset tracking and/or remove existing anchors if consistent tracking is required
    
}

@end

scn 格式文件是一个基于 3D 建模的文件,使用 3DMax 软件可以创建,这里系统有一个默认的 3D 飞机。

效果:

  1. 飞机能够随着摄像头位置的变化而看到不同的部位(六轴);
  2. 飞机能够随着摄像头的远近进行缩放。

ARConfiguration:提供 3DOF 追踪

ARWorldTrackingConfiguration:提供 6DOF 追踪

自由度( DOF,Degree Of Freedom )表示描述系统状态的独立参数的个数。

DOF.png

对于 3DOF 追踪,我们旋转设备时可以看到虚拟的飞机视角有所变化;但当平移时,我们可以看到飞机是随着设备进行移动的。
对于 6DOF 追踪,我们旋转设备时可以看到虚拟的飞机视角有所变化(这点与 3DOF 追踪没有区别);平移时,我们可以看到飞机的不同位置,例如向上平移看到了飞机的上表面,围着飞机平移可以看到飞机的四周,而 3DOF 没有提供这种平移的追踪。

可以通过 [ARWorldTrackingConfiguration isSupported] 判断设备是否支持ARWorldTrackingConfiguration


AR初体验之2D效果

  1. 打开 Xcode ,新建一个工程,选择 Augmented Reality APP (Xcode 9 新增),点击 Next。
  2. 在包含技术选项中选择 SpriteKit。
  3. 此时,Xcode 也会自动为我们生成一段极其简洁的 AR 代码。
#import "ViewController.h"
#import "Scene.h"

@interface ViewController () <ARSKViewDelegate>

@property (nonatomic, strong) IBOutlet ARSKView *sceneView;

@end


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Set the view's delegate
    // 设置场景视图代理
    self.sceneView.delegate = self;
    
    // Show statistics such as fps and node count
    // 显示帧率
    self.sceneView.showsFPS = YES;
    // 显示界面节点(游戏开发中,一个角色对应一个节点)
    self.sceneView.showsNodeCount = YES;
    
    // Load the SKScene from 'Scene.sks'
    // 加载2D场景(2D是平面的)
    Scene *scene = (Scene *)[SKScene nodeWithFileNamed:@"Scene"];
    
    // Present the scene
    // AR预览视图展示场景(这一点与3D视图加载有区别)
    [self.sceneView presentScene:scene];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    // Create a session configuration
    // 创建设备追踪设置
    ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];

    // Run the view's session
    // 开始启动AR
    [self.sceneView.session runWithConfiguration:configuration];
}

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

#pragma mark - ARSKViewDelegate
//点击界面会调用,类似于touch begin方法  anchor是2D坐标的瞄点
- (SKNode *)view:(ARSKView *)view nodeForAnchor:(ARAnchor *)anchor {
    // Create and configure a node for the anchor added to the view's session.
    // 创建节点(节点可以理解为AR将要展示的2D图像)
    SKLabelNode *labelNode = [SKLabelNode labelNodeWithText:@"😜"];
    labelNode.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    labelNode.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
    return labelNode;
}

- (void)session:(ARSession *)session didFailWithError:(NSError *)error {
    // Present an error message to the user
    
}

- (void)sessionWasInterrupted:(ARSession *)session {
    // Inform the user that the session has been interrupted, for example, by presenting an overlay
    
}

- (void)sessionInterruptionEnded:(ARSession *)session {
    // Reset tracking and/or remove existing anchors if consistent tracking is required
    
}

@end

END


场景交互(Hit-testing)理解

Hit-testing 是为了获取当前捕捉到的图像中某点击位置有关的信息(包括平面、特征点、ARAnchor 等)。
[图片上传失败...(image-ba8a3e-1554264132836)]
当点击屏幕时,ARKit 会发射一个射线,假设屏幕平面是三维坐标系中的 xy 平面,那么该射线会沿着 z 轴方向射向屏幕里面,这就是一次 Hit-testing 过程。此次过程会将射线遇到的所有有用信息返回,返回结果以离屏幕距离进行排序,离屏幕最近的排在最前面。

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

ARHitTestResultTypeFeaturePoint:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的 3D 特征点。
ARHitTestResultTypeEstimatedHorizontalPlane:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的预估平面。预估平面表示 ARKit 当前检测到一个可能是平面的信息,但当前尚未确定是平面,所以 ARKit 还没有为此预估平面添加 ARPlaneAnchor。
ARHitTestResultTypeEstimatedVerticalPlane:同上,区别仅是预估竖面。
ARHitTestResultTypeExistingPlane:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的无限大小的平面。
ARHitTestResultTypeExistingPlaneUsingExtent:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的有大小范围的平面。
ARHitTestResultTypeExistingPlaneUsingGeometry:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的有大小范围和形状的平面。


参考文档

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