iOS AR开发基础02 | ARKit开发基本套路和核心API

上一篇从直观体验上介绍了“什么是AR”,本篇接着上篇内容,从技术层面对AR技术进行分析,提炼出其中的开发基本套路和一些最基础的API。

写在前面

构建AR应用,涉及到两大块内容 ,对真实世界的理解和追踪3D AR世界的渲染以及用户和3D世界的交互,这二者分别对应 ARKitSceneKit 两个框架。

本文会以 ARKit 和 SceneKit 中的 API为例,来讲解 AR 项目构建的基本原理和主要流程,如果您是初学者,对这两个框架不熟悉,刚开始不必太过纠结于某一处细节,从宏观上把握整个流程即可。

关于 ARKit 相关的内容,在大致熟悉整个流程之后,可以查看 《iOS AR开发基础篇03 -- Hello World (基于AR的平面检测、人脸检测和物体识别功能)》文中给出的 demo来加深理解。

关于 SceneKit相关的内容 ,本文会给出一些相关名词,重在理解其意,在《 iOS AR开发基础篇04 -- SceneKit开发基础(3D渲染基础)》中会给出具体API的使用和细节。

如果要了解具体 API 的一些细节,可以在 Apple 官方文档中查看相应内容。

本文内容结构

本文内容结构如下:

iOS AR开发基础02 | ARKit开发基本套路和核心API_第1张图片
本节内容概览

1. AR系统的结构

先从宏观上给出一张AR系统的结构:

iOS AR开发基础02 | ARKit开发基本套路和核心API_第2张图片
AR System architecture-1

这张图很重要,本文的内容都是围绕这张图展开的。

对这张AR系统的结构图,从整体上,我们可以粗略的做如下解析:

  • 在图示最左侧的是真实世界,我们通过camera获取真实世界的信息
  • 我们将获取到的真实世界信息进行理解
  • 基于场景理解,将虚拟世界渲染到真实世界的指定位置
  • 从而在屏幕上就展示了一个增强现实的世界(AR World)
  • 我们可以通过点击屏幕的方式和虚拟世界进行交互,虚拟世界响应交互之后,重新渲染
  • 当我们移动设备的时候,捕获到的真实世界变化了,需要重新理解场景、重新渲染AR世界

我们知道基本套路之后,开发的时候,需要将具体的步骤和相应的API对应起来,如下图:

iOS AR开发基础02 | ARKit开发基本套路和核心API_第3张图片
AR System architecture-2

这张图的5种颜色大框,对应5个模块,框里面对应的就是每个模块核心类和核心的API,下面详细讲解每个模块。

2. 虚拟世界

2.1 2D/3D引擎介绍

ARKit本身并不提供渲染引擎,在虚拟世界的构建时,我们需要用到其它的2D/3D引擎,对于没有3D开发经验的同学来说,我认为学习AR开发,70%的精力都会花在此处。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第4张图片
虚拟世界

图示用的是用SceneKit中的SCNScene构建虚拟3D世界,这种方式是苹果推荐使用的,因为ARKit中提供了很多便利方法可以供我们直接使用。例如,我们查看ARKit中负责呈现视图的ARSceneView定义不难发现,它是SCNView的子类。

open class ARSCNView : SCNView {
// ...
}

后续开发我们也会使用SceneKit作为3D内容渲染引擎,SpriteKit作为2D内容渲染引擎。
后续开发我们也会使用SceneKit作为3D内容渲染引擎,SpriteKit作为2D内容渲染引擎。
后续开发我们也会使用SceneKit作为3D内容渲染引擎,SpriteKit作为2D内容渲染引擎。
(重要的事儿说三遍!)
当然,Apple还有其他的2D/3D引擎提供:

  • Metal
  • OpenGL
  • Unity3D
  • Unreal Engine

2.2 SceneKit中的坐标系

如图所示的三维坐标系,就是SceneKit所使用的坐标系,它是一个右手坐标系

iOS AR开发基础02 | ARKit开发基本套路和核心API_第5张图片
SceneKit - Coordinate

此图上的每一个方块代表空间中的一个点,其中:

  • 灰色方块:坐标系原点,坐标为(0,0,0)
  • 红色方块:X轴上的点,坐标可以表示为(x-value,0,0)
  • 青色方块:Y轴上的点,坐标可以表示为(0,y-value,0)
  • 蓝色方块:Z轴上的点,坐标可以表示为(0,0,z-value)

2.2.1 世界坐标系

2.2.2 本地坐标系

在SceneKit中,我们用SCNVector3来表示一个三维的点,空间中创建一个坐标为(1,1,1)点的方式如下:

     let position = SCNVector3(x:1, y: 1, z: 1)

2.3 SceneKit中的 SCNScene 和 SCNNode

我们先想象一个拍电影的场景。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第6张图片
image.png

在SceneKit中,我们可以把SCNCamera当做拍摄镜头,SCNScene当做拍摄场景,场景中的每个人或者物体都可以看做SCNNode,在指定的坐标系下,每个SCNNode都有唯一的坐标。
在下图实线为坐标轴所表示的坐标系下,三个小黑点表示场景(scene)中的三个节点(node),其中RootNode称之为根节点,NodeA和NodeB称之为非根节点。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第7张图片
SCNNode

此处要引出两个重要的概念:世界坐标系本地坐标系

  • 世界坐标系:以根节点为原点创建的三维坐标系称为世界坐标系
  • 本地坐标系:以非根节点为原点创建的三维坐标系称为本地坐标系

节点的位置是相对的父节点的本地坐标。

在上图中,在以RootNode为坐标原地的世界坐标系中,RootNode是NodeA的父节点,NodeA是RootNode的子节点。

而在以NodeA为坐标原点的本地坐标系中,NodeA是NodeB的父节点,NodeB是NodeA的子节点。

有了SCNScene和SCNNode 后,我们还需要一个 SCNCamera 来决定我们可以看到场景中的哪一块区域。

2.4 SceneKit 中的 SCNCamera

SCNCamera 在 SCNScene 的工作模式如下图所示:

iOS AR开发基础02 | ARKit开发基本套路和核心API_第8张图片
SCNCamera

通过观察我们发现:

  • SCNCamera始终捕获 -Z 方向的场景
  • X-Field of View:在X方向上的视野范围,在xFOV之外的区域不可见
  • Y-Field of View:在Y方向上的视野范围,在yFOV之外的区域不可见
  • Viewing Frustum:在Z方向上的视野范围,在zNear和zFar之外的区域不可见

在SceneKit中,创建一个SCNCamera实例并将其添加到cameraNode上,再将cameraNode设置为场景中的根节点,代码如下:

let scene = SCNScene()
let cameraNode = SCNNode()
let camera = SCNCamera()
cameraNode.camera = camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 0)
scene.rootNode.addChildNode(cameraNode)

2.5 SceneKit 中的 SCNView

SCNView用来将SCNScene的内容展示到屏幕上,其基本用法如下:

  • 创建一个SCNView实例
  • 将上面我们创建的scene实例设置SCNView的scene属性
  • 将SCNView实例添加到UIKit的UIView或者UIWindow上

代码如下:

let scnView = SCNView()
scnView.scene = scene
vc.view.addSubview(scnView)
scnView.frame = vc.view.bounds

3. 捕获真实世界

摄像头捕获真实的世界的图像作为AR世界的背景显示,使用的过程中,涉及到三个核心类:ARSession、ARFrame和ARCamera。


iOS AR开发基础02 | ARKit开发基本套路和核心API_第9张图片
Capture Real World

3.1 ARSession

ARSession 是一个单例,用来管理、配置整个AR体验的主要流程,它包括:

  • 从设备的运动传感器读取数据
  • 控制摄设备内置摄像头,利用AVCaptureSession捕获实时的图像
  • 对捕获到的图像进行分析,并对外输出ARFrame实例
  • 综合运动数据和图像分析结果,建立起真实世界和虚拟世界的对应关系

每一个基于ARKit的AR项目都需要一个ARSession对象。
如果使用ARSCNView/ARSKView对象来渲染AR内容,他们本身包含一个ARSession属性session;如果自定义AR内容渲染器,就需要自行实例化和维护ARSession对象。

ARSCNView 和 ARSession 关系如下:

open class ARSCNView : SCNView {
// ...
    /**
     The session that the view uses to update the scene.
     */
    open var session: ARSession
// ...
}

运行session,还需要一个ARConfiguration(或它子类ARWorldTrackingConfiguration)实例configuration。configuration将决定ARKit如何跟踪设备相对于真实世界的位置和运动,从而影响创建的AR体验种类。

运行一个session基础代码如下:

 // Create a session configuration.
let configuration = ARWorldTrackingSessionConfiguration()
 // Create a session.
 let session = ARSession()
 // Run.
 session.run(configuration)

3.2 ARFrame

ARFrame实例是带有位置追踪信息(position-tracking information)的视频图像,对于ARFrame有以下三个要点:

  • 正在运行的AR session会不断捕捉设备摄像头的视频帧。
  • 对于每一帧,ARKit都会结合来自设备运动传感硬件的数据进行分析,以估算设备的实际位置
  • ARKit通过ARFrame向外传递当前帧的位置信息图像参数

查看ARFrame头文件,本节我们先掌握它的如下四个属性:

open class ARFrame : NSObject, NSCopying {
    // ...
    /**
     A timestamp identifying the frame.
     */
    open var timestamp: TimeInterval { get }
    /**
     The frame’s captured image.
     */
    open var capturedImage: CVPixelBuffer { get }

    /**
     A list of anchors in the scene.
     */
    open var anchors: [ARAnchor] { get }

    /**
     The camera used to capture the frame’s image.
     @discussion The camera provides the device’s position and orientation as well as camera parameters.
     */
    @NSCopying open var camera: ARCamera { get }
    // ...
}

  • capturedImage:当前帧的原始数据
  • timestamp:当前帧的时间戳
  • anchors:这个数组包含的是一系列的锚点对象,在当前场景中,每个锚点表示一个跟踪的位置一个检测到的对象,后面有内容终点讲述ARAnchor类,此处了解即可
  • camera:只读参数,返回获取当前帧的camera,在本文的世界追踪部分会介绍ARCamera

至此,我们不仅获取了图像的原始数据,还获取到了图像中的位置追踪信息和其它的图像参数。

4. 世界追踪

世界追踪(World Tracking)将虚拟世界和真实世界联系起来,这里追踪的“世界”是“真实世界”。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第10张图片
World Tracking

ARSession是整个世界追踪的核心类,连接虚拟世界和真实世界需要运行ARSession实例,运行方式和前面“捕获真实世界”中的方式一样,此处不再赘述。追踪原理大致如下:

  • ARSession 使用 AVCaptureSession 捕获实时的图像
  • ARSession 使用 CMMotionManager 追踪设备的移动数据
  • 图像处理结束完成之后 ARSession 输出 ARFrames

4.1 世界追踪基本原理

iOS AR开发基础02 | ARKit开发基本套路和核心API_第11张图片
image.png

获取原始位置

设备在运行ARSession时的初始位置。

可以追踪什么?

  • 设备的相对位置和方向
  • 物理距离(真实世界的实际距离),以米为单位计量
  • 正在追踪的点的位置

怎么追踪?

  • 3D特征点:当前场景检测到的3D坐标点,这些点表示当前场景的特征
  • 设备移动的数据:来自设备的传感器硬件
  • 视觉惯性测距法:结合3D特征点和设备移动的数据,来计算该设备的位置和运动的高精度模型

追踪质量的影响因素

影响世界追踪的主要因素有

  • 连续的位移传感器数据
  • 检测的环境有纹理,不能是纯色的
  • 静态的场景

追踪状态

这是camera的一个状态机,在触发不同事件后,追踪状态会切换,详细内容会在【4.2.4 ARCamera】中讲解。


iOS AR开发基础02 | ARKit开发基本套路和核心API_第12张图片
camera的追踪状态机

4.2 相关API

前面已经介绍过ARSession、ARCamera和ARFrame了,现在介绍一下如下几个类:

  • 和configuration相关的ARWorldTrackingConfiguration、AROrientationTrackingConfiguration 类
  • 和追踪结果相关的ARPlaneAnchor 类
  • 获取世界追踪状态信息的 ARSessionDelegate

4.2.1 ARWorldTrackingConfiguration

ARWorldTrackingConfiguration可以将虚拟世界和真实世界联系起来,这样当虚拟世界和真实世界同时渲染在屏幕上的时候,用户会产生虚拟内容是真实世界的一部分的错觉。

运行 session 的时候,若将configuration参数设为 ARWorldTrackingConfiguration,ARKit将会:

  • 调用系统后置摄像头
  • 追踪设备方向
  • 追踪设备位置
  • 检测真实世界的平面

维护真实世界和虚拟世界的对应关系,我们还需要获取设备的移动信息。ARWorldTrackingConfiguration类从6个自由度(degrees of freedom)来追踪设备的运动:具体来说,三个旋转轴(滚动,俯仰和偏航)以及三个平移轴(在X,Y和Z中的移动)。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第13张图片
6DOF

这种追踪可以给用户带来沉浸式的体验:虚拟世界的物体可以看起来与现实世界保持相同的位置,即使用户将设备倾斜到物体的上方或下方,或者移动设备以查看物体的侧面和背面。

如下是Apple官方文档中给的一张图,无论设备旋转或移动,6DOF跟踪都会保持AR的良好体验。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第14张图片
6DOF tracking maintains an AR illusion regardless of device rotation or movement

ARWorldTrackingConfiguration 的部分头文件如下:

open class ARWorldTrackingConfiguration : ARConfiguration {

    // ... 
    /**
     Type of planes to detect in the scene.
     @discussion If set, new planes will continue to be detected and updated over time. Detected planes will be added to the session as
     ARPlaneAnchor objects. In the event that two planes are merged, the newer plane will be removed. Defaults to ARPlaneDetectionNone.
     */
    open var planeDetection: ARWorldTrackingConfiguration.PlaneDetection

    
    /**
     Images to detect in the scene.
     @discussion If set the session will attempt to detect the specified images. When an image is detected an ARImageAnchor will be added to the session.
     */
    @available(iOS 11.3, *)
    open var detectionImages: Set?

    // ... 
}

planeDetection
设置这个属性,可以指定是否检测当前摄像头捕获图像中的平面。

planeDetection 是一个 ARWorldTrackingConfiguration.PlaneDetection类型的值,它可以取两个值 horizontalvertical,分别代表水平面检测和垂直面检测。

其中,垂直平面检测是iOS 11.3支持的功能。

  /**
     Option set indicating the type of planes to detect.
     */
    @available(iOS 11.0, *)
    public struct PlaneDetection : OptionSet {

        // ... 
        /** Plane detection determines horizontal planes in the scene. */
        public static var horizontal: ARWorldTrackingConfiguration.PlaneDetection { get }

        /** Plane detection determines vertical planes in the scene. */
        @available(iOS 11.3, *)
        public static var vertical: ARWorldTrackingConfiguration.PlaneDetection { get }
        // ...
    }

默认情况下,平面检测是关闭状态。如果启用水平或垂直平面检测,session 在捕获的视频图像中分析检测到平面区域时,会自动添加一个 ARPlaneAnchor 对象,并给实现 ARSessionDelegate、ARSCNViewDelegate 或 ARSKViewDelegate 的对象发送通知。ARPlaneAnchor 在后面将会讲解。

detectionImages
detectionImages 也是一个iOS 11.3支持的AR图像识别功能。后面会写一个Demo来实现这个功能。

4.2.2 AROrientationTrackingConfiguration

和 ARWorldTrackingConfiguration 类似,设置 AROrientationTrackingConfiguration 属性之后:

  • 调用系统后置摄像头
  • 只追踪设备方向
  • 不追踪设备位置
  • 不检测真实世界的平面

还是引用Apple官方文档中给的图片。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第15张图片
3DOF tracking maintains an AR illusion when the the device pivots, but not when the device's position moves

4.2.3 ARPlaneAnchor

anchor翻译为锚点,在世界追踪的AR session 中,一个ARPlaneAnchor对象表示在真实世界中,一个平面的位置和方向信息。

/**
 An anchor representing a planar surface in the world.
 @discussion Planes are defined in the X and Z direction, where Y is the surface’s normal.
 */
@available(iOS 11.0, *)
open class ARPlaneAnchor : ARAnchor {
}

ARPlaneAnchor 是 ARAnchor 的子类,在看 ARPlaneAnchor 之前,先看看ARAnchor。

ARAnchor

锚点表示真实世界的位置和方向,为AR场景中放置虚拟物体提供位置信息。在开发的过程中,需要掌握对anchor的如下操作:

  • 手动向ARSession 中添加、移除锚点:如果需要追踪真实世界中的某个点,创建一个锚点对象,然后用add(anchor:)方法将其添加到session中
  • 获取ARSession 中的所有锚点:session.currentFrame.anchors
  • ARKit自动添加锚点:如果开启了平面检测,系统为检测到的平面自动添加锚点
  • ARSessionDelegate:实现该delegate,可以接收到锚点添加、更新和移除的通知

其实ARAnchor的定义比较简单,包含两个属性:

  • identifier :唯一表示锚点
  • transform:用 matrix_float4x4 表示锚点位置信息,三维空间中的位置为什么需要用一个四维的数据来表示?后面单独篇幅来讲解这个问题
/**
 Object representing a physical location and orientation in 3D space.
 */
@available(iOS 11.0, *)
open class ARAnchor : NSObject, NSCopying, NSSecureCoding {

    
    /**
     Unique identifier of the anchor.
     */
    open var identifier: UUID { get }

    /**
     The transformation matrix that defines the anchor’s rotation, translation and scale in world coordinates.
     */
    open var transform: matrix_float4x4 { get }

    /**
     Initializes a new anchor object.
     @param transform The transformation matrix that defines the anchor’s rotation, translation and scale in world coordinates.
     */
    public init(transform: matrix_float4x4)
}
ARPlaneAnchor

注意:iOS 11.3之前只支持水平面检测,11.3开始支持垂直面检测!

当运行启用了 planeDetection 选项的世界追踪AR session时,每检测到一个平面,ARKit 会自动将表示该平面的ARPlaneAnchor对象添加到一个数组中去。 每个ARPlaneAnchor对象提供关于平面的位置和形状的信息。

ARPlaneAnchor 在 ARAnchor 基础上添加了和“平面”相关的三个属性alignmentcenterextentgeometry:

**
 An anchor representing a planar surface in the world.
 @discussion Planes are defined in the X and Z direction, where Y is the surface’s normal.
 */
@available(iOS 11.0, *)
open class ARPlaneAnchor : ARAnchor {

    /**
     The alignment of the plane.
     */
    open var alignment: ARPlaneAnchor.Alignment { get }

    /**
     The center of the plane in the anchor’s coordinate space.
     */
    open var center: vector_float3 { get }

    /**
     The extent of the plane in the anchor’s coordinate space.
     */
    open var extent: vector_float3 { get }

    /**
     Geometry of the plane in the anchor's coordinate space.
     */
    @available(iOS 11.3, *)
    open var geometry: ARPlaneGeometry { get }
}
  • extent 和 center 属性比较好理解,就是平面的中心点和大小;
  • alignment 描述这个平面相对重力的方向,可以取两个值 horizontal 和 vertical(iOS 11.3+);
  • geometry 也是 iOS 11.3新增的属性,可以辅助我们做可视化

4.2.4 ARCamera

ARCamera作为ARFrame的属性,在ARSession捕获视频帧数据的时候,从以下三方面了解ARCamera:

  • camera的位置信息
  • camera的成像特性
  • camera的追踪状态
camera的位置信息

和位置相关的信息通过两个属性来描述,transform 和 eulerAngles,前者表示位置,后者表示方向。

open class ARCamera : NSObject, NSCopying {
    // ... ...
    /**
     The transformation matrix that defines the camera’s rotation and translation in world coordinates.
     */
    open var transform: matrix_float4x4 { get }

    
    /**
     The camera’s orientation defined as Euler angles.
     
     @dicussion The order of components in this vector matches the axes of rotation:
                   1. Pitch (the x component) is the rotation about the node’s x-axis (in radians)
                   2. Yaw   (the y component) is the rotation about the node’s y-axis (in radians)
                   3. Roll  (the z component) is the rotation about the node’s z-axis (in radians)
                ARKit applies these rotations in the reverse order of the components:
                   1. first roll
                   2. then yaw
                   3. then pitch
     */
    open var eulerAngles: vector_float3 { get }
     // ... ...
}

成像特性信息

intrinsicsimageResolution 两个属性描述了ARCamera成像特性,设置这两个参数可以想象成给真实的相机调参。


open class ARCamera : NSObject, NSCopying {
     // ... ...
    /**
     The camera intrinsics.
     @discussion The matrix has the following contents:
     fx 0   px
     0  fy  py
     0  0   1
     fx and fy are the focal length in pixels.
     px and py are the coordinates of the principal point in pixels.
     The origin is at the center of the upper-left pixel.
     */
    open var intrinsics: matrix_float3x3 { get }

    /**
     The camera image resolution in pixels.
     */
    open var imageResolution: CGSize { get }
     // ... ...
}

intrinsics 称之为相机的内参,是相机的一个固有属性,也就是说每个相机都会有 Intrinsic Matrix,因为所有的相机都需要将现实世界中3D空间的点映射到捕捉的图像中2D空间的点。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第16张图片
3D空间的点N映射到捕捉的图像中2D空间的点N'

Intrinsic Matrix 一般是形式如下:

iOS AR开发基础02 | ARKit开发基本套路和核心API_第17张图片
Intrinsic Matrix

其中,

  • fx 和 fy 是摄像机镜头的焦距
  • ox 和 oy 则是点 M(成像平面与 z 轴交点)相对于点 O(成像平面二维坐标系原点)的 x 与 y 方向的偏移

后续有文章来描述这个内参的推倒过程。

imageResolution 属性理解起来就相对简单一些,图像的分辨率,以像素为单位表示 ARCamera 捕获图像的宽度和高度。

处理追踪状态

追踪状态通过两个属性来描述,trackingStatetrackingStateReason,前者表示ARCamera当前的状态,当状态为 limited 的时候,trackingStateReason输出原因。

open class ARCamera : NSObject, NSCopying {
     // ... ...
    /**
     The tracking state of the camera.
     */
    open var __trackingState: __ARTrackingState { get }

    
    /**
     The reason for the camera’s current tracking state.
     */
    open var __trackingStateReason: __ARTrackingStateReason { get }
     // ... ...
}

trackingState是一个 ARCamera.TrackingState类型变量,有三个状态可供切换:

  • notAvailable:ARCamera 位置追踪不可用
  • limited:ARCamera 位置追踪可用,但是结果的质量有问题,此时有
  • normal:ARCamera 位置追踪可以正在输出可用结果
/**
     A value describing the camera's tracking state.
     */
    public enum TrackingState {

        /** Tracking is not available. */
        case notAvailable

        /** Tracking is limited. See tracking reason for details. */
        case limited(ARCamera.TrackingState.Reason)

        /** Tracking is normal. */
        case normal
    }

当 trackingState 为 limited 的时候,可以获取原因:

  • initializing:ARCamera正在初始化
  • excessiveMotion:手机移动的幅度太大了
  • insufficientFeatures:缺少特征点
  • relocalizing:正在重新定位,追踪收到限制(iOS 11.3)
public enum Reason {

            /** Tracking is limited due to initialization in progress. */
            case initializing

            /** Tracking is limited due to a excessive motion of the camera. */
            case excessiveMotion

            /** Tracking is limited due to a lack of features visible to the camera. */
            case insufficientFeatures

            /** Tracking is limited due to a relocalization in progress. */
            @available(iOS 11.3, *)
            case relocalizing
        }

4.2.5 ARSessionDelegate

ARSessionDelegate 一共有四个optional 方法,可以将这四个方法拆分为两部分:

  • 接收捕获的视频帧图像
  • 处理内容更新
接收捕获的视频帧图像

通过ARFrame实例获取静态图像,前面讲过,此处不赘述。

    /**
     This is called when a new frame has been updated.
     
     @param session The session being run.
     @param frame The frame that has been updated.
     */
    optional public func session(_ session: ARSession, didUpdate frame: ARFrame)
处理内容更新

通过下面三个方法,可以追踪场景中锚点的添加、更新和移除状态。

    /**
     This is called when new anchors are added to the session.
     
     @param session The session being run.
     @param anchors An array of added anchors.
     */
    optional public func session(_ session: ARSession, didAdd anchors: [ARAnchor])

    /**
     This is called when anchors are updated.
     
     @param session The session being run.
     @param anchors An array of updated anchors.
     */
    optional public func session(_ session: ARSession, didUpdate anchors: [ARAnchor])
    
    /**
     This is called when anchors are removed from the session.

     @param session The session being run.
     @param anchors An array of removed anchors.
     */
    optional public func session(_ session: ARSession, didRemove anchors: [ARAnchor])

5. 场景理解(Scene Understanding)

理解真实世界的目的,是为了将虚拟物体放置在真实世界中,场景理解需要掌握三个要点:

  • 平面检测(Plane detection)
  • 碰撞测试(Hit-testing)
  • 光照估计 (Lighting estimation)

平面检测

上一节内容已经讲过,ARKit可检测场景中的平面(水平方向、垂直方向),检测到平面之后,会自动添加锚点,我们通过ARSessionDelegate可以获取锚点的更新状态,相关API前面也有讲解,此处不再赘述。

碰撞测试

碰撞测试要这么理解,前面我们讲过 ARCamera 将真实世界的3D场景转换到2D屏幕上,Hit-testing 就是一个还原的过程,将屏幕上的点还原到3D空间中去。理解完原理之后,一切就变得很简单了。

下图形象的展示了一次Hit-testing。用户点击屏幕之后,在AR空间中模拟发射一条射线,射线所经过的线路上的锚点都会作为结果被返回,所以Hit-testing的返回结果是一个数组,但是不是直接将锚点添加到数组中,而是将锚点封装成 ARHitTestResult 对象后,按照离用户的距离排序放入一个数组中。所以图示中这次Hit-testing返回结果中包含三个元素。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第18张图片
Hit-testing

对应的API如下,开发中我们拿到ARHitTestResult数组之后,一般情况下,我们会遍历这个数组,从中获取我们感兴趣的ARHitTestResult对象。

 /**
     Searches the current frame for objects corresponding to a point in the view.
     
     @discussion A 2D point in the view’s coordinate space can refer to any point along a line segment
     in the 3D coordinate space. Hit-testing is the process of finding objects in the world located along this line segment.
     @param point A point in the view’s coordinate system.
     @param types The types of results to search for.
     @return An array of all hit-test results sorted from nearest to farthest.
     */
    open func hitTest(_ point: CGPoint, types: ARHitTestResult.ResultType) -> [ARHitTestResult]

光照估计

光照估计是 ARConfiguration 的一个属性,打开之后渲染虚拟物体的时候,会适应环境的光线情况,这样AR世界看着更逼真。

    /**
     Enable or disable light estimation.
     @discussion Enabled by default.
     */
    open var isLightEstimationEnabled: Bool

6. 渲染

如下如所示,虚拟世界、捕获的真实世界、世界追踪的信息和场景理解信息一起参与渲染,形成AR世界。


iOS AR开发基础02 | ARKit开发基本套路和核心API_第19张图片
Rendering

由于渲染是 SceneKit 来完成的,相关渲染的API在后续文章中详细讲解。

参考

  • ARKit Documentation

至此,对整个AR系统的框架结构有了宏观上的理解。
下一篇,将会写一个Hello World的AR demo。

iOS AR开发基础02 | ARKit开发基本套路和核心API_第20张图片
感谢

你可能感兴趣的:(iOS AR开发基础02 | ARKit开发基本套路和核心API)