Bloodline's Blog Notes and thoughts from Bloodline

ARKit(二)——核心类介绍

Comments

核心类介绍

ARAnchor

ARAnchor 表示一个物体在 3D 空间的位置和方向,通常称为物体的 3D 锚点,有点像 UIKit 框架中 CALayer 的 Anchor。

@interface ARAnchor : NSObject <NSCopying>

/**
 锚点的标识符
 */
@property (nonatomic, readonly) NSUUID *identifier;

/**
 锚点的旋转变换矩阵,定义了锚点的旋转、位置、缩放。是一个4x4的矩阵。
 */
@property (nonatomic, readonly) matrix_float4x4 transform;

/**
 构造方法。一般不需要调用,因为添加一个 3D 物体时 ARKit 会通过代理告知我们物体的锚点。
 */
- (instancetype)initWithTransform:(matrix_float4x4)transform;

@end

ARCamera

ARCamera 是连接虚拟场景与现实场景之间的枢纽。在 ARKit 中,它是捕捉现实图像的相机,在 SceneKit 中它是 3D 虚拟世界中的相机。(一般第一人称3D游戏,主角其实就是一个3D相机,我们电脑屏幕看到的画面就是这个相机捕捉的画面)

一般无需去创建一个相机,因为初始化 AR 视图时,会为我们默认创建相机,而且这个相机就是摄像头的位置,同时也是 3D 世界中的原点所在(x=0,y=0,z=0)。

/**
 描述相机追踪状态的值
 */
API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
typedef NS_ENUM(NSInteger, ARTrackingState) {
    /** 不被允许 */
    ARTrackingStateNotAvailable,
    
    /** 追踪被限制,参考 ARTrackingStateReason */
    ARTrackingStateLimited,
    
    /** 正常 */
    ARTrackingStateNormal,
} NS_REFINED_FOR_SWIFT;

/**
 描述为何相机追踪状态被限制的原因
 */
API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
typedef NS_ENUM(NSInteger, ARTrackingStateReason) {
    /** 追踪未限制 */
    ARTrackingStateReasonNone,
    
    /** 正在进行初始化追踪被限制 */
    ARTrackingStateReasonInitializing,
    
    /** 跟踪由于相机移动过度而受到限制 */
    ARTrackingStateReasonExcessiveMotion,
    
    /** 相机由于缺少特征值,追踪受到限制 */
    ARTrackingStateReasonInsufficientFeatures,
} NS_REFINED_FOR_SWIFT;

@interface ARCamera : NSObject <NSCopying>

/**
 4x4 矩阵表示相机位置,同 ARAnchor。在世界坐标中定义摄像机旋转和平移的变换矩阵。
 */
@property (nonatomic, readonly) matrix_float4x4 transform;

/**
 相机方向(旋转)的矢量欧拉角,分别是x/y/z
 
 @dicussion 向量中元素的顺序与旋转轴相匹配:
               1. Pitch (x) 手机的俯仰(弧度)
               2. Yaw   (y) 绕着垂直于手机屏幕的轴旋转(弧度)
               3. Roll  (z) 绕着手机的向上方向旋转(弧度)
            ARKit 以相反的顺序应用这些旋转:
               1. 首先 roll
               2. 然后 yaw
               3. 最后 pitch
 */
@property (nonatomic, readonly) vector_float3 eulerAngles;

/**
 相机的追踪状态
 */
@property (nonatomic, readonly) ARTrackingState trackingState NS_REFINED_FOR_SWIFT;

/**
 相机的追踪状态的原因
 */
@property (nonatomic, readonly) ARTrackingStateReason trackingStateReason NS_REFINED_FOR_SWIFT;

/**
 相机的 intrinsics
 @discussion 3x3 矩阵,这个矩阵将我们现实世界中三维坐标系的点映射到相机捕捉的图像中:
 fx 0   px
 0  fy  py
 0  0   1
 fx 和 fy 是像素的焦距
 px 和 py 是像素点的坐标
 原点位于左上角的像素中心
 */
@property (nonatomic, readonly) matrix_float3x3 intrinsics;

/**
 摄像头分辨率
 */
@property (nonatomic, readonly) CGSize imageResolution;

/**
 相机投影矩阵
*/
@property (nonatomic, readonly) matrix_float4x4 projectionMatrix;

/**
 将世界坐标系统的三维点投射到二维视窗空间。
 
 @param point 世界坐标系统中的三维点坐标
 @param orientation Viewport 方向
 @param viewportSize Viewport(或 image)的尺寸
 @return 返回基于 viewport 坐标系统的 2D 坐标,原点位于左上角。
 */
- (CGPoint)projectPoint:(vector_float3)point orientation:(UIInterfaceOrientation)orientation viewportSize:(CGSize)viewportSize;

/**
 为给定参数的相机创建投影矩阵
 
 @discussion 返回的投影矩阵包含 viewport 的大小和方向的平面
 @param orientation Viewport 方向
 @param viewportSize Viewport 尺寸
 @param zNear 近面距离
 @param zFar 远面距离
 */
- (matrix_float4x4)projectionMatrixForOrientation:(UIInterfaceOrientation)orientation viewportSize:(CGSize)viewportSize zNear:(CGFloat)zNear zFar:(CGFloat)zFar;

/**
 为给定方向的相机创建投影矩阵
 
 @discussion 视图矩阵可用于将几何物体转换为给定方向的相机空间
 @param orientation 用于渲染相机视图的界面朝向
 */
- (matrix_float4x4)viewMatrixForOrientation:(UIInterfaceOrientation)orientation;

@end

ARError

ARKit 框架中描述错误的类。错误来源于设备不支持,或者当相机常驻后台时 ARSession 断开等。

//作用域,一般会表示是哪一个类出现问题
FOUNDATION_EXTERN NSString *const ARErrorDomain;

typedef NS_ERROR_ENUM(ARErrorDomain, ARErrorCode) {
    /** 不支持会话追踪配置,A9 芯片以下的机型会报错 */
    ARErrorCodeUnsupportedConfiguration   = 100,
    
    /** 运行会话所需的传感器不可用 */
    ARErrorCodeSensorUnavailable          = 101,
    
    /** 传感器未能提供所需的输入 */
    ARErrorCodeSensorFailed               = 102,
    
    /** 应用程序没有使用相机的权限。用户可以在设置中进行更改 */
    ARErrorCodeCameraUnauthorized         = 103,
    
    /** 追踪错误 */
    ARErrorCodeWorldTrackingFailed        = 200,
};

ARFrame

摄像头视频帧的包装类,包含位置追踪信息、环境参数、视频帧。

@interface ARFrame : NSObject <NSCopying>

/**
 时间戳,用于标识 frame。
 */
@property (nonatomic, readonly) NSTimeInterval timestamp;

/**
 彩色摄像头采集的颜色信息
 */
@property (nonatomic, readonly) CVPixelBufferRef capturedImage;

/**
 深度摄像头采集的深度信息
 */
@property (nonatomic, strong, readonly, nullable) AVDepthData *capturedDepthData;

/**
 capturedDepthData 的时间戳,实测下来在帧率60的情况下,每4帧里有1帧包含深度信息
 */
@property (nonatomic, readonly) NSTimeInterval capturedDepthDataTimestamp;

/**
 捕获图像的相机
 */
@property (nonatomic, copy, readonly) ARCamera *camera;

/**
 返回当前相机捕捉到的锚点数据
 */
@property (nonatomic, copy, readonly) NSArray<ARAnchor *> *anchors;

/**
 灯光,如果不设置可能为 nil
 */
@property (nonatomic, strong, nullable, readonly) ARLightEstimate *lightEstimate;

/**
 特征点
 */
@property (nonatomic, strong, nullable, readonly) ARPointCloud *rawFeaturePoints;

/**
 根据2D坐标点搜索3D模型,这个方法通常用于,当我们在手机屏幕点击某一个点的时候,可以捕捉到这一个点所在的3D模型的位置,至于为什么是一个数组非常好理解。手机屏幕一个是长方形,这是一个二维空间。而相机捕捉到的是一个由这个二维空间射出去的长方体,我们点击屏幕一个点可以理解为在这个长方体的边缘射出一条线,这一条线上可能会有多个3D物体模型
 point:2D坐标点(手机屏幕某一点)(点在被捕获图像的图像空间坐标系统中。取值范围从(0,0)-左上角到(1,1)-右下角。)
 ARHitTestResultType:捕捉类型  点还是面(类型的搜索结果类型)
 (NSArray<ARHitTestResult *> *):追踪结果数组  详情见 ARHitTestResult 类介绍
 */
- (NSArray<ARHitTestResult *> *)hitTest:(CGPoint)point types:(ARHitTestResultType)types;

/**
 返回提供的viewport大小和方向的显示转换。
 可以用来转换图像空间坐标系统中的归一化点在视图的坐标空间中被捕获的图像到归一化点。转换提供了正确的旋转并在给定的方向和大小中显示捕获的图像。
 定位视图端口的朝向。
 */
- (CGAffineTransform)displayTransformForOrientation:(UIInterfaceOrientation)orientation viewportSize:(CGSize)viewportSize;

@end

ARHitTestResult

点击回调结果,这个类主要用于虚拟增强现实技术(AR技术)中现实世界与3D场景中虚拟物体的交互。 比如我们在相机中移动。拖拽3D虚拟物体,都可以通过这个类来获取ARKit所捕捉的结果。

/**
 hittest结果类型的选项集。
 捕捉类型枚举
 */
typedef NS_OPTIONS(NSUInteger, ARHitTestResultType) {
    /** 与最近的特征点相交的结果类型 */
    ARHitTestResultTypeFeaturePoint              = (1 << 0),

    /** 与当前帧确定的水平面相交的结果类型 */
    ARHitTestResultTypeEstimatedHorizontalPlane  = (1 << 1),
    
    /** 与现有平面锚点相交的结果类型 */
    ARHitTestResultTypeExistingPlane             = (1 << 3),
    
    /** 与现有平面锚点(考虑平面的范围)相交的结果类型,并考虑平面的范围 */
    ARHitTestResultTypeExistingPlaneUsingExtent  = (1 << 4),
} NS_SWIFT_NAME(ARHitTestResult.ResultType);

@interface ARHitTestResult : NSObject

/**
 测试结果的类型 : 捕捉类型
 */
@property (nonatomic, readonly) ARHitTestResultType type;

/**
 从相机到交叉口的距离 : 3D虚拟物体与相机的距离(单位:米)
 */
@property (nonatomic, readonly) CGFloat distance;

/**
 这个变换矩阵定义了交叉的旋转,平移和缩放相对于锚或最近的特征点 
 本地坐标矩阵(世界坐标指的是相机为场景原点的坐标,而每一个3D物体自身有一个场景,本地坐标就是相对于这个场景的坐标)类似于frame和bounds的区别
 */
@property (nonatomic, readonly) matrix_float4x4 localTransform;

/**
 这个变换矩阵定义了交叉的旋转,平移和缩放相对于这个世界 : 世界坐标矩阵
 */
@property (nonatomic, readonly) matrix_float4x4 worldTransform;

/**
 hit- test交叉的锚, 只会为现有的飞机结果类型提供锚点.
 锚点(3D虚拟物体,在虚拟世界有一个位置,这个位置参数是SceneKit中的SCNVector3:三维矢量),而锚点anchor是这个物体在AR现实场景中的位置,是一个4x4的矩阵
 */
@property (nonatomic, strong, nullable, readonly) ARAnchor *anchor;

@end

ARLightEstimate

ARLightEstimate 提供灯光效果,可以让 AR 场景更真实。

@interface ARLightEstimate : NSObject

/**
 照明的环境强度。
 在一个照明良好的环境中,这个值接近1000。它通常从0(非常暗)到大约2000(非常明亮)。
 */
@property (nonatomic, readonly) CGFloat ambientIntensity;

/**
 灯光的环境色温。
 这指定了开尔文(6500对应于纯白色)照明的环境色温。
*/
@property (nonatomic, readonly) CGFloat ambientColorTemperature;

@end

ARDirectionalLightEstimate

ARDirectionalLightEstimate 是 ARLightEstimate 的子类。

@interface ARDirectionalLightEstimate : ARLightEstimate

/**
 二次球面谐波系数,表示光强
 
 数据是27个32位浮点值的数组,包含三个非交织数据集,对应于红色,绿色和蓝色系数组
 */
@property (nonatomic, copy, readonly) NSData *sphericalHarmonicsCoefficients;

/**
 光的主要方向
 */
@property (nonatomic, readonly) vector_float3 primaryLightDirection;

/**
 主要方向的光强度
 */
@property (nonatomic, readonly) CGFloat primaryLightIntensity;

@end

ARPlaneAnchor

ARPlaneAnchor 是 ARAnchor 的子类,可以理解为平面锚点。ARKit 能够自动识别平面,并且会默认添加一个锚点到场景中,当然要想看到真实世界中的平面效果,需要使用 SCNNode 来渲染这个锚点。锚点只是一个位置

@interface ARPlaneAnchor : ARAnchor

/**
 平面类型,目前只有一个,就是水平面(ARPlaneAnchorAlignmentHorizontal)
 */
@property (nonatomic, readonly) ARPlaneAnchorAlignment alignment;

/**
 3 轴矢量结构体,表示平面的中心点  x/y/z
 */
@property (nonatomic, readonly) vector_float3 center;

/**
 3 轴矢量结构体,表示平面的大小(宽度和高度)  x/y/z
 */
@property (nonatomic, readonly) vector_float3 extent;

@end

ARPointCloud

ARPointCloud,点状渲染云,主要用于渲染场景。

@interface ARPointCloud : NSObject

/**
 点的数量
 */
@property (nonatomic, readonly) NSUInteger count NS_REFINED_FOR_SWIFT;

/**
 每一个点的位置的集合(结构体带*表示的是结构体数组)
 */
@property (nonatomic, readonly) const vector_float3 *points NS_REFINED_FOR_SWIFT;

/**
 包括点云的 3D 点标识符
 */
@property (nonatomic, readonly) const uint64_t *identifiers NS_REFINED_FOR_SWIFT;

@end

ARSCNView

辅助视图,主要功能是将 SceneKit 渲染的 3D 内容渲染到相机的实时图像上,从而实现 AR 体验的视图。ARSCNView 继承于 框架中的 SCNView,而 SCNView 又继承于 框架中的 UIView。这个类主要做了以下的事情:

  • 从设备相机中取到实时的画面,并渲染到 3D 场景中作为背景。

  • ARKit 的三维坐标系可以与 SceneKit 的三维坐标系进行匹配。因此,在这个视图中渲染出的对象能够自动匹配到 ARKit 的世界坐标。

  • 自动移动虚拟的 SceneKit 相机去匹配在真实世界中的由 ARKit 跟踪的 3D 坐标,因此我们不需要写代码来将移动事件与 SceneKit 的 3D 图像进行关联。

由于 ARKit 会自动将 SceneKit 空间与真实世界相匹配,所以要放置一个虚拟物品让它显示在真实世界的位置上,只需要给它设置一个合适的 SceneKit 坐标即可。我们并不需要使用 ARAnchor 类去追踪你添加在场景中的物体的坐标,但是还是需要实现 ARSCNViewDelegate 中的方法,这样才可以在 ARKit 自动检测的任何一个锚点上添加 SceneKit 的内容。

需要注意的是:渲染 3D 物体的功能是父类 SCNView 就具备的功能,而捕捉 3D 现实场景并进行相应坐标计算转换的是 ARSCNView(也就是 ARKit)的实现的功能。

@interface ARSCNView : SCNView

/**
 代理
 */
@property (nonatomic, weak, nullable) id<ARSCNViewDelegate> delegate;

/**
 ARSession
 */
@property (nonatomic, strong) ARSession *session;

/**
 指定 SCNScene
 */
@property(nonatomic, strong) SCNScene *scene;

/**
 是否自动适应灯光,默认是 YES
 */
@property(nonatomic) BOOL automaticallyUpdatesLighting;

/**
 返回对应节点的锚点,节点是一个 3D 虚拟物体,它的坐标是虚拟场景中的坐标,而锚点 ARAnchor 是 ARKit 中现实世界的坐标。
 */
- (nullable ARAnchor *)anchorForNode:(SCNNode *)node;

/**
 返回对应锚点的物体
 */
- (nullable SCNNode *)nodeForAnchor:(ARAnchor *)anchor;

/**
 根据2D坐标点搜索3D模型,这个方法通常用于,当我们在手机屏幕点击某一个点的时候,可以捕捉到这一个点所在的 3D 模型的位置,至于为什么是一个数组非常好理解。手机屏幕一个是长方形,这是一个二维空间。而相机捕捉到的是一个由这个二维空间射出去的长方体,点击屏幕一个点可以理解为在这个长方体的边缘射出一条线,这一条线上可能会有多个 3D 物体模型。
 @param point 2D 坐标点(手机屏幕某一点)
 @param types 点击结果类型
 @return An array of all hit-test 追踪结果数组 详情见 ARHitTestResult 类介绍,数组的结果排序是由近到远
 */
- (NSArray<ARHitTestResult *> *)hitTest:(CGPoint)point types:(ARHitTestResultType)types;

@end

#pragma mark - ARSCNViewDelegate

/**
 代理的内部实现了 SCNSceneRendererDelegate:scenekit 代理和 ARSessionObserver:ARSession 监听(KVO机制)
 */
@protocol ARSCNViewDelegate <SCNSceneRendererDelegate, ARSessionObserver>
@optional

/**
 为给定的锚提供一个自定义节点。如果没有实现,则节点会自动创建,如果返回 nil,锚点会被忽略。

 @param renderer 渲染场景的渲染器
 @param anchor 添加的锚点
 @return Node 锚点对应的节点
 */
- (nullable SCNNode *)renderer:(id <SCNSceneRenderer>)renderer nodeForAnchor:(ARAnchor *)anchor;

/**
 当添加节点时会调用,我们可以通过这个代理方法得知我们添加一个虚拟物体到 AR 场景下的锚点(AR 现实世界中的坐标)

 @param renderer 渲染场景的渲染器
 @param node 锚点对应的节点
 @param anchor 添加的锚点
 */
- (void)renderer:(id <SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor;

/**
 当节点将从给定的锚点更新数据时调用。
 
 @param renderer 渲染场景的渲染器
 @param node 将要更新的节点
 @param anchor 更新过的锚点
 */
- (void)renderer:(id <SCNSceneRenderer>)renderer willUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor;

/**
 当节点已从给定的锚点更新数据时调用。
 
 @param renderer 渲染场景的渲染器
 @param node 更新过的节点
 @param anchor 更新过的锚点
 */
- (void)renderer:(id <SCNSceneRenderer>)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor;

/**
 当给定的锚点被从场景图中移除时调用。
 
 @param renderer 渲染场景的渲染器
 @param node 被移除的节点
 @param anchor 被移除的锚点
 */
- (void)renderer:(id <SCNSceneRenderer>)renderer didRemoveNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor;

@end

/**
 ARSCNView 的扩展调试选项
 */
struct ARSCNDebugOptions {} API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos);

/** 在场景中展示世界起源  */
FOUNDATION_EXTERN const SCNDebugOptions ARSCNDebugOptionShowWorldOrigin NS_SWIFT_NAME(ARSCNDebugOptions.showWorldOrigin);

/** 显示在世界上检测到的3D特征点  */
FOUNDATION_EXTERN const SCNDebugOptions ARSCNDebugOptionShowFeaturePoints NS_SWIFT_NAME(ARSCNDebugOptions.showFeaturePoints);

ARSession

ARSession 是一个连接底层与 AR 视图之间的桥梁,其实 ARSCNView 内部所有的代理方法都是由 ARSession 来提供的。每个用 ARKit 建立的 AR 场景都需要一个 ARSession 对象。它负责控制相机,从设备中收集所有的传感器数据(包括从设备的运动传感器中读取数据,控制设备的相机,对相机中捕获到的图像进行分析),来建立用户所在的现实世界与 AR 模型的内容空间之间的联系。ARSCNView 实例已经包含一个 ARSession 实例,只需要在启动的时候进行配置(ARSessionConfiguration 或其子类 ARWorldTrackingSessionConfiguration)就可以了。

ARSession 获取相机位置数据主要有两种方式:一种是通过实现 ARSession 的代理 didUpdateFrame 来实现,另外一种是通过 ARSession 的属性 currentFrame 来获取。

/**
 运行 ARSession 的选项。选项会改变 ARSession 运行的方式。不设置的话,将会从上一个已知位置针对所有锚点进行追踪
 */
API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
typedef NS_OPTIONS(NSUInteger, ARSessionRunOptions) {
    /** ARSession 重置追踪 */
    ARSessionRunOptionResetTracking           = (1 << 0),
    
    /** ARSession 将删除所有锚点 */
    ARSessionRunOptionRemoveExistingAnchors   = (1 << 1)
} NS_SWIFT_NAME(ARSession.RunOptions);

@interface ARSession : NSObject

/**
 接收 ARSession 更新的代理对象
 */
@property (nonatomic, weak) id <ARSessionDelegate> delegate;

/**
 代理回调的 dispatch queue
 @discussion 不设置的话,将会在主线程回调
 */
@property (nonatomic, strong, nullable) dispatch_queue_t delegateQueue;

/**
 相机当前的位置(是由 ARSession 追踪配置计算出来的)
 */
@property (nonatomic, copy, nullable, readonly) ARFrame *currentFrame;

/**
 ARSession 的配置
 */
@property (nonatomic, copy, nullable, readonly) ARConfiguration *configuration;

/**
 使用给定的配置运行
 @discussion 如果已经运行了,则会更新配置后继续运行
 @param configuration 运行配置
 */
- (void)runWithConfiguration:(ARConfiguration *)configuration NS_SWIFT_UNAVAILABLE("Use run(_:options:) instead");

/**
 使用给定的配置和选项运行
 @discussion 如果已经运行了,则会更新配置后继续运行。选项可用于在更换配置时改变默认的方式
 @param configuration 运行配置
 @param options 运行选项
 */
- (void)runWithConfiguration:(ARConfiguration *)configuration options:(ARSessionRunOptions)options NS_SWIFT_NAME(run(_:options:));

/**
 暂停
 @discussion 暂停后不会接收更新,除非再次调用 run 方法
 */
- (void)pause;

/**
 添加锚点 
 @discussion 锚点会在下一帧更新时添加
 @param anchor 要添加的锚点.
 */
- (void)addAnchor:(ARAnchor *)anchor NS_SWIFT_NAME(add(anchor:));

/**
 移除锚点
 @discussion 锚点会在下一帧时移除
 @param anchor 要移除的锚点
 */
- (void)removeAnchor:(ARAnchor *)anchor NS_SWIFT_NAME(remove(anchor:));

@end

/**
 session代理分类两部分,一个是观察者(KVO) 一个是委托者(代理)
 */
#pragma mark - ARSessionObserver

/**
 观察者(KVO)
 */
@protocol ARSessionObserver <NSObject>

@optional

/**
 session 失败时调用
 
 @discussion 失败时会暂停
 @param session 失败的 session
 @param error 错误,可以参考 ARError.h
 */
- (void)session:(ARSession *)session didFailWithError:(NSError *)error;

/**
 相机的追踪状态改变时调用
 
 @param session 运行的 session
 @param camera 追踪状态的相机
 */
- (void)session:(ARSession *)session cameraDidChangeTrackingState:(ARCamera *)camera;

/**
 session 被中断时调用
 
 @discussion 当 session 无法从传感器接收到数据时,会断开,停止追踪。图像被中断时便会发生,比如 APP 切到后台,或多个前台应用(参考 AVCaptureSessionInterruptionReason)。此时 frame 直到恢复才会再进行更新。
 @param session 被中断的 session
 */
- (void)sessionWasInterrupted:(ARSession *)session;

/**
 session 中断恢复时调用
 
 @discussion 中断恢复时,session 可以继续从上一个已知状态运行。如果设备移动过,则锚点会错位。要避免这种情况,APP 最好重置追踪(参考 ARSessionRunOptions)
 @param session 被中断的 session
 */
- (void)sessionInterruptionEnded:(ARSession *)session;

/**
 当会话输出一个新的音频样本缓冲区时,调用这个方法。
 
 @param session 运行的 session
 @param audioSampleBuffer 获取的音频样本缓冲区
 */
- (void)session:(ARSession *)session didOutputAudioSampleBuffer:(CMSampleBufferRef)audioSampleBuffer;

@end

#pragma mark - ARSessionDelegate


API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
@protocol ARSessionDelegate <ARSessionObserver>

@optional

/**
 更新相机状态(空间位置,图像帧等)
 
 @param session 运行的 session
 @param frame 更新过的 frame
 */
- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame;

/**
 session 添加新锚点时调用
 
 @param session 运行的 session
 @param anchors 要添加的锚点
 */
- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor*>*)anchors;

/**
 锚点更新时调用
 
 @param session 运行的 session
 @param anchors 要更新的锚点
 */
- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor*>*)anchors;

/**
 锚点被移除时调用
 
 @param session 运行的 session
 @param anchors 移除的锚点
 */
- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor*>*)anchors;

@end

ARConfiguration

最近更新的 ARKit 中 ARSessionConfiguration 已经变为 ARConfiguration。子类 ARWorldTrackingSessionConfiguration 也改为 ARWorldTrackingConfiguration。

ARWorldTrackingConfiguration

这个类可以在 6 个自由维度上(six degrees of freedom, 6DOF)追踪设备的移动, 也就是 3 个旋转轴(roll:绕着垂直于手机屏幕的轴旋转,yaw:绕着手机的向上方向旋转,pitch:改变手机的俯仰),3 个平移轴(在 x, y, z 上的移动)。这样我们可以围绕虚拟物体进行查看,设置可以移动虚拟物体。如果没有这样的需求,并且用户并不会在虚拟体验中改变位置,那可以使用 ARConfiguration 来初始化 ARSession 实例。

/**
 追踪对齐方式枚举,ARKit 如何基于真实设备运动构建场景坐标系统(参照物)
 */
API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
typedef NS_ENUM(NSInteger, ARWorldAlignment) {
    /** y 轴与设备运动传感硬件检测到的重力方向相匹配;即向量(0,-1,0)向下指向。 */
    ARWorldAlignmentGravity,
    
    /** y 轴与设备运动传感硬件检测到的重力方向相匹配;即向量(0,-1,0)向下指向
        x 轴和 z 轴与定位服务所测量的经度和纬度方向相匹配。矢量(0,0,-1)指向正北,矢量(-1,0,0)指向西。
     */
    ARWorldAlignmentGravityAndHeading,
    
    /** 场景坐标系被锁定以匹配相机的方向 */
    ARWorldAlignmentCamera
} NS_SWIFT_NAME(ARConfiguration.WorldAlignment);


/**
 平面检测类型
 */
API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
typedef NS_OPTIONS(NSUInteger, ARPlaneDetection) {
    /** 没有进行平面检测 */
    ARPlaneDetectionNone        = 0,
    
    /** 水平平面检测 */
    ARPlaneDetectionHorizontal  = (1 << 0),
} NS_SWIFT_NAME(ARWorldTrackingConfiguration.PlaneDetection);

API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos)
@interface ARConfiguration : NSObject <NSCopying>

/**
 当前设备是否支持
 */
@property(class, nonatomic, readonly) BOOL isSupported;

/**
 确定坐标系与世界的对齐方式,默认是 ARWorldAlignmentGravity
 */
@property (nonatomic, readwrite) ARWorldAlignment worldAlignment;

/**
 是否需要自适应灯光效果,默认是 YES
 */
@property (nonatomic, readwrite, getter=isLightEstimationEnabled) BOOL lightEstimationEnabled;

/**
 确定是否采集和提供音频数据,默认不可以。
 */
@property (nonatomic, readwrite) BOOL providesAudioData;

@end

@interface ARWorldTrackingConfiguration : ARConfiguration

/**
 在场景中检测到的平面的类型
 @discussion 设置后,新的平面将继续被检测并随时间更新。检测到的平面会被当做 ARPlaneAnchor 对象添加到 session 中。两个平面合并时,后添加的平面会被移除。默认是 ARPlaneDetectionNone。
 */
@property (nonatomic, readwrite) ARPlaneDetection planeDetection;

@end

参考:

ARKit

ARKit从入门到精通