美文网首页
iOS多媒体:AR

iOS多媒体:AR

作者: 时光啊混蛋_97boy | 来源:发表于2020-08-27 14:25 被阅读0次

原创:知识探索型文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

目录

  • 1、概念
  • 2、设备追踪
  • 3、ARFrame
  • 4、场景解析
  • 5、SceneKit
  • Demo
  • 参考文献

1、概念

AR 全称 Augmented Reality(增强现实)是一种在视觉上呈现虚拟物体与现实场景结合的技术。Apple 公司在 2017 年正式推出了ARKit,iOS 开发者可以在这个平台上使用简单便捷的 API 来开发 AR 应用程序。为了获得 ARKit的完整功能,需要A9 及以上芯片。

AR 的全称是增强现实,通过显示屏与各类传感器,能让虚拟世界中创作出的物品与现实世界产生交互。

技术方面,现有 AR 解决方案已经可以检测并记录虚拟物品在现实环境中的准确位置、分辨虚拟物品与现实中物品的遮挡关系、为虚拟物体增加在现实中的光源与阴影、让虚拟物品与现实中的物品产生交互等。就像其它新技术一样,AR 的具体使用场景仍处于探索阶段,下面是我在关注的几个使用角度。

游戏 - 沉浸与代入感:说到虚拟现实的应用,许多人可能都会想到游戏。起先我并没太注意这些所谓 AR 游戏与直接在手机里玩有什么区别,直到前一阵子,精灵宝可梦支持了 AR 模式,允许你把宝可梦放在世界中

在真实世界中与宝可梦互动的体验让我意识到,在手机中与模型交互,给人直观的感觉始终是在和屏幕互动,无论模型和场景搭建的有多精致,用户感知到的始终只是屏幕。将模型放在现实世界中,无论你怎么移动手机,它还在那里。虽然仍旧摸不到,但能看到它出现在日常生活中,熟悉的现实里,带来的沉浸与代入感完全不同。

当我打开 AR 应用时,恍然意识到三维模型本就应该空间概念。建筑学用二维的三视图来避免图纸与模型潜在的不确定因素,呈现在空间中的三维模型则可以彻底避免这个问题,人可以自然地走动来确定所有细节。

若你将 AR 的技术开发进度想象成建造一辆车,ARKit 的定位便是配件,之后的所有功能都建立在这个基础之上。ARKit 中提供一些与 AR 相关的核心能力,如:提供景深信息来判断物体在空间中的位置、用空间锚点来记录虚拟物品在真实世界中的经纬度及海拔坐标、用摄像头对面部信息进行追踪等。下图中,图标下方的阴影及切换角度后物品位置不变的特性,便是 ARKit 提供的基础能力。

原深感镜头组

许多人了解这个镜头组件是因为 iPhone X 发布会上的面容 ID,替换了传统指纹识别来用于安全的验证身份。实际上原深感镜头组用途不仅于身份验证,它会投射 30,000 多个不可见的点来来获取准确的深度数据,这些数据对 AR 很有帮助。前置摄像头所做的摄像时背景替换,脸上试戴墨镜这类 AR 应用,许多都是通过 ARKit 调用原深感摄像头组件的硬件来实现的。

针对 AR 模型的技术准备 USDZ

市面上 3D 建模软件众多,各家选用的导出格式也差异非常大。为解决素材格式不统一的问题,Apple 与皮克斯合作推出了 USDZ 模型封装格式。此后 AR 场景所采用的素材均需为 USDZ ,避免了项目中各类文件混杂的情况。USDZ 自身也是个实力派,支持将模型的动画,纹理材质等众多与模型相关的内容,全部封装在一个文件中。

空间感知芯片 U 系列

U 系列是在 iPhone 设备中新增的超宽带 UWB 芯片,它能提供在较大空间内极度精准定位的能力。举个例子,若你的 AirPods Pro 找不到了,配备 U 系列芯片的手机可以准确指向该耳机的准确方向与距离。现有 AR 技术主要基于摄像头,当用户脱离摄像头区域后,便会丢失目标,若用户携带 Air Tag 定位器,则可能用 U 芯片进行定位,来实现许多之前无法做到的场景。虽 Apple 暂时还没开放它在 AR 场景的应用,但 U 系列芯片给开发者提供了许多想象力。

iOS 平台的 AR 应用通常由 ARKit 和渲染引擎两部分构成:

架构

ARKitARSession 负责管理每一帧的信息。ARSession 做了两件事,拍摄图像并获取传感器数据,对数据进行分析处理后逐帧输出。如下图:

ARSession

2、设备追踪

a、启动 ARSession

设备追踪确保了虚拟物体的位置不受设备移动的影响。在启动 ARSession时需要传入一个 ARSessionConfiguration的子类对象,以区别三种追踪模式:ARFaceTrackingConfigurationARWorldTrackingConfigurationAROrientationTrackingConfiguration。其中 ARFaceTrackingConfiguration 可以识别人脸的位置、方向以及获取拓扑结构。此外,还可以探测到预设的 52 种丰富的面部动作,如眨眼、微笑、皱眉等等。ARFaceTrackingConfiguration 需要调用支持 TrueDepth 的前置摄像头进行追踪。以ARWorldTrackingConfiguration为例进行追踪,获取特征点。

// 创建一个 ARSessionConfiguration
let configuration = ARWorldTrackingSessionConfiguration()

// Create a session
let session = ARSession()

// Run
session.run(configuration)
b、ARSession 底层如何进行世界追踪
  1. ARSession 底层使用了 AVCaputreSession 来获取摄像机拍摄的视频(一帧一帧的图像序列)。
  2. ARSession 底层使用了CMMotionManager 来获取设备的运动信息(比如旋转角度、移动距离等)
  3. ARSession 根据获取的图像序列以及设备的运动信息进行分析,最后输出 ARFrameARFrame 中就包含有渲染虚拟世界所需的所有信息。
ARSession 底层如何进行世界追踪 ARSession 底层如何进行世界追踪
c、追踪信息点

AR-World 的坐标系如下,当我们运行 ARSession 时设备所在的位置就是 AR-World 的坐标系原点。

AR-World的坐标系

在这个 AR-World 坐标系中,ARKit 会追踪以下几个信息:

  • 追踪设备的位置以及旋转,这里的两个信息均是相对于设备起始时的信息。
  • 追踪物理距离(以“米”为单位),例如 ARKit 检测到一个平面,我们希望知道这个平面有多大。
  • 追踪我们手动添加的希望追踪的点,例如我们手动添加的一个虚拟物体。
d、追踪如何工作

ARKit使用视觉惯性测距技术,对摄像头采集到的图像序列进行计算机视觉分析,并且与设备的运动传感器信息相结合。ARKit 会识别出每一帧图像中的特征点,并且根据特征点在连续的图像帧之间的位置变化,然后与运动传感器提供的信息进行比较,最终得到高精度的设备位置和偏转信息。

追踪如何工作

上图中划出曲线的运动的点代表设备,可以看到以设备为中心有一个坐标系也在移动和旋转,这代表着设备在不断的移动和旋转。这个信息是通过设备的运动传感器获取的。

动图中右侧的黄色点是 3D 特征点。3D特征点就是处理捕捉到的图像得到的,能代表物体特征的点。例如地板的纹理、物体的边边角角都可以成为特征点。上图中我们看到当设备移动时,ARKit 在不断的追踪捕捉到的画面中的特征点。

ARKit 将上面两个信息进行结合,最终得到了高精度的设备位置和偏转信息。

e、ARWorldTrackingConfiguration

ARWorldTrackingConfiguration 提供 6DoFSix Degree of Freedom)的设备追踪。包括三个姿态角 Yaw(偏航角)、Pitch(俯仰角)和 Roll(翻滚角),以及沿笛卡尔坐标系中 XYZ 三轴的偏移量。

ARWorldTrackingConfiguration

不仅如此,ARKit 还使用了 VIOVisual-Inertial Odometry)来提高设备运动追踪的精度。在使用惯性测量单元(IMU)检测运动轨迹的同时,对运动过程中摄像头拍摄到的图片进行图像处理。将图像中的一些特征点的变化轨迹与传感器的结果进行比对后,输出最终的高精度结果。

从追踪的维度和准确度来看,ARWorldTrackingConfiguration非常强悍。但它也有两个致命的缺点:受环境光线质量影响和受剧烈运动影响。由于在追踪过程中要通过采集图像来提取特征点,所以图像的质量会影响追踪的结果。在光线较差的环境下(比如夜晚或者强光),拍摄的图像无法提供正确的参考,追踪的质量也会随之下降。追踪过程中会逐帧比对图像与传感器结果,如果设备在短时间内剧烈的移动,会很大程度上干扰追踪结果。

e、追踪状态

世界追踪有三种状态,我们可以通过 camera.trackingState 获取当前的追踪状态。

追踪状态

从上图我们看到有三种追踪状态:

Not Available// 世界追踪正在初始化,还未开始工作
Normal// 正常工作状态
Limited// 限制状态,当追踪质量受到影响时,追踪状态可能会变为 Limited 状态

TrackingState 关联的一个信息是ARCamera.TrackingState.Reason,这是一个枚举类型:

case excessiveMotion// 设备移动过快,无法正常追踪
case initializing// 正在初始化
case insufficientFeatures// 特征过少,无法正常追踪
case none// 正常工作

我们可以通过 ARSessionObserver 协议去获取追踪状态的变化。

3、ARFrame

a、ARFrame

ARFrame 中包含有世界追踪过程获取的所有信息,ARFrame 中与世界追踪有关的信息主要是:anchorscamera

//camera: 含有摄像机的位置、旋转以及拍照参数等信息
var camera: [ARCamera]

//ahchors: 代表了追踪的点或面
var anchors: [ARAnchor]
b、ARAnchor

ARAnchor 是空间中相对真实世界的位置和角度。ARAnchor 可以添加到场景中,或是从场景中移除。基本上来说,它们用于表示虚拟内容在物理环境中的锚定,所以如果要添加自定义 anchor,添加到 session 里就可以了,它会在 session 生命周期中一直存在。但如果你在运行诸如平面检测功能,ARAnchor 则会被自动添加到 session 中。

要响应被添加的 anchor,可以从 current ARFrame 中获得完整列表,此列表包含 session 正在追踪的所有 anchor。或者也可以响应 delegate方法,例如 addupdate 以及 removesession 中的 anchor 被添加、更新或移除时会通知。

c、ARCamera
ARCamera

每个 ARFrame 都会包含一个 ARCameraARCamera 对象表示虚拟摄像头。虚拟摄像头就代表了设备的角度和位置。

  • ARCamera提供了一个transformtransform 是一个4x4矩阵。提供了物理设备相对于初始位置的变换。
  • ARCamera 提供了追踪状态(tracking state),通知你如何使用 transform
  • ARCamera 提供了相机内部功能(camera intrinsics)。包括焦距和主焦点,用于寻找投影矩阵。投影矩阵是 ARCamera 上的一个 convenience 方法,可用于渲染虚拟你的几何体。

4、场景解析

场景解析主要功能是对现实世界的场景进行分析,解析出比如现实世界的平面等信息,可以让我们把一些虚拟物体放在某些实物处。ARKit 提供的场景解析主要有平面检测、场景交互以及光照估计三种,下面逐个分析。

场景解析
a、平面检测(Plane detection)

ARKit 的平面检测用于检测出现实世界的水平面。

平面检测

❶ 上图中可以看出,ARkit 检测出了两个平面,图中的两个三维坐标系是检测出的平面的本地坐标系,此外,检测出的平面是有一个大小范围的。

❷ 平面检测是一个动态的过程,当摄像机不断移动时,检测到的平面也会不断的变化。下图中可以看到当移动摄像机时,已经检测到的平面的坐标原点以及平面范围都在不断的变化。

平面检测

❸ 开启平面检测很简单,只需要在 run ARSession 之前,将 ARSessionConfigurationplaneDetection 属性设为 true 即可。

// Create a world tracking session configuration.
let configuration = ARWorldTrackingSessionConfiguration()
configuration.planeDetection = .horizontal

// Create a session.
let session = ARSession()

// Run.
session.run(configuration)

平面的表示方式:ARKit检测到一个平面时,ARKit会为该平面自动添加一个 ARPlaneAnchor,这个 ARPlaneAnchor 就表示了一个平面。

❺ 当 ARKit 系统检测到新平面时,ARKit 会自动添加一个 ARPlaneAnchorARSession 中。我们可以通过 ARSessionDelegate 获取当前 ARSessionARAnchor 改变的通知,主要有以下三种情况:

新加入了 ARAnchor:对于平面检测来说,当新检测到某平面时,我们会收到该通知,通知中的 ARAnchor 数组会包含新添加的平面,其类型是 ARPlaneAnchor

func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
    for anchor in anchors {
        if let anchor = anchor as? ARPlaneAnchor {
            print(anchor.center)
            print(anchor.extent)
        }
    }
}

ARAnchor更新:从上面我们知道当设备移动时,检测到的平面是不断更新的,当平面更新时,会回调这个接口。

func session(_ session: ARSession, didUpdate anchors: [ARAnchor])

删除 ARAnchor:当手动删除某个 Anchor 时就会回调此方法。此外,对于检测到的平面来说,如果两个平面进行了合并,则会删除其中一个,此时也会回调此方法。

func session(_ session: ARSession, didRemove anchors: [ARAnchor])
b、场景交互(Hit-testing)

Hit-testing 是为了获取当前捕捉到的图像中某点击位置有关的信息(包括平面、特征点、ARAnchor 等)。原理图如下:

场景交互

当点击屏幕时,ARKit会发射一个射线,假设屏幕平面是三维坐标系中的 xy 平面,那么该射线会沿着 z 轴方向射向屏幕里面,这就是一次 Hit-testing 过程。此次过程会将射线遇到的所有有用信息返回,返回结果以离屏幕距离进行排序,离屏幕最近的排在最前面。

ARFrame 提供了Hit-testing的接口:

func hitTest(_ point: CGPoint, types: ARHitTestResult.ResultType) -> [ARHitTestResult]

上述接口中有一个 types 参数,该参数表示此次 Hit-testing 过程需要获取的信息类型,ResultType 有以下四种。

featurePoint:表示此次 Hit-testing 过程希望返回当前图像中Hit-testing 射线经过的 3D 特征点。

featurePoint

estimatedHorizontalPlane:表示此次 Hit-testing 过程希望返回当前图像中 Hit-testing 射线经过的预估平面。预估平面表示 ARKit 当前检测到一个可能是平面的信息,但当前尚未确定是平面,所以 ARKit 还没有为此预估平面添加 ARPlaneAnchor

estimatedHorizontalPlane

existingPlaneUsingExtent:表示此次Hit-testing过程希望返回当前图像中Hit-testing射线经过的有大小范围的平面。

existingPlaneUsingExtent

existingPlane:表示此次Hit-testing过程希望返回当前图像中Hit-testing射线经过的无限大小的平面。

existingPlane

上图中,平面大小是绿色平面所展示的大小,但exsitingPlane选项表示即使Hit-testing射线落在了绿色平面外面,也会将此平面返回。换句话说,将所有平面无限延展,只要 Hit-testing 射线经过了无限延展后的平面,就会返回该平面。

Demo演示:Hit-testingpoint(0.5, 0.5)代表屏幕的中心,屏幕左上角为(0, 0),右下角为(1, 1)。 对于 featurePointestimatedHorizontalPlane 的结果,ARKit没有为其添加ARAnchor,我们可以使用Hit-testing获取信息后自己为ARSession 添加 ARAnchor,下面代码就显示了此过程。

// Adding an ARAnchor based on hit-test
let point = CGPoint(x: 0.5, y: 0.5)  // Image center

// Perform hit-test on frame.
let results = frame. hitTest(point, types: [.featurePoint, .estimatedHorizontalPlane])

// Use the first result.
if let closestResult = results.first {
    // Create an anchor for it.
    anchor = ARAnchor(transform: closestResult.worldTransform)
    // Add it to the session.
    session.add(anchor: anchor)
}
c、光照估计(Light estimation)

下图中,一个虚拟物体茶杯被放在了现实世界的桌子上。

光照估计

当周围环境光线较好时,摄像机捕捉到的图像光照强度也较好,此时,我们放在桌子上的茶杯看起来就比较贴近于现实效果,如上图最左边的图。但是当周围光线较暗时,摄像机捕捉到的图像也较暗,如上图中间的图,此时茶杯的亮度就显得跟现实世界格格不入。

针对这种情况,ARKit 提供了光照估计,开启光照估计后,我们可以拿到当前图像的光照强度,从而能够以更自然的光照强度去渲染虚拟物体,如上图最右边的图。

光照估计基于当前捕捉到的图像的曝光等信息,给出一个估计的光照强度值(单位为lumen,光强单位)。默认的光照强度为 1000lumen,当现实世界较亮时,我们可以拿到一个高于 1000lumen 的值,相反,当现实世界光照较暗时,我们会拿到一个低于 1000lumen的值。

ARKit 的光照估计默认是开启的,当然也可以通过下述方式手动配置:

configuration.isLightEstimationEnabled = true

获取光照估计的光照强度也很简单,只需要拿到当前的 ARFrame,通过以下代码即可获取估计的光照强度:

let intensity = frame.lightEstimate?.ambientIntensity

5、SceneKit

a、简介

渲染是呈现AR world的最后一个过程。此过程将创建的虚拟世界、捕捉的真实世界、ARKit 追踪的信息以及 ARKit场景解析的的信息结合在一起,渲染出一个 AR world。渲染过程需要实现以下几点才能渲染出正确的 AR world

  • 将摄像机捕捉到的真实世界的视频作为背景。
  • 将世界追踪到的相机状态信息实时更新到 AR world 中的相机。
  • 处理光照估计的光照强度。
  • 实时渲染虚拟世界物体在屏幕中的位置。
SceneKit

如果我们自己处理这个过程,可以看到还是比较复杂的,ARKit为简化开发者的渲染过程,为开发者提供了简单易用的使用SceneKit(3D 引擎)以及 SpriteKit(2D 引擎)渲染的视图ARSCNView以及ARSKView。当然开发者也可以使用其他引擎进行渲染,只需要将以上几个信息进行处理融合即可。

b、SceneKit 的坐标系

我们知道 UIKit使用一个包含有 xy信息的 CGPoint 来表示一个点的位置,但是在 3D 系统中,需要一个z参数来描述物体在空间中的深度,SceneKit 的坐标系可以参考下图:

SceneKit 的坐标系

这个三维坐标系中,表示一个点的位置需要使用(x,y,z)坐标表示。红色方块位于x轴,绿色方块位于 y轴,蓝色方块位于z轴,灰色方块位于原点。在SceneKit中我们可以这样创建一个三维坐标:

let position = SCNVector3(x: 0, y: 5, z: 10)
c、SceneKit 中的场景和节点

我们可以将 SceneKit 中的场景(SCNScene)想象为一个虚拟的 3D 空间,然后可以将一个个的节点(SCNNode)添加到场景中。SCNScene 中有唯一一个根节点(坐标是(x:0, y:0, z:0)),除了根节点外,所有添加到 SCNScene 中的节点都需要一个父节点。

下图中位于坐标系中心的就是根节点,此外还有添加的两个节点 NodeANodeB,其中 NodeA的父节点是根节点,NodeB 的父节点是 NodeA

SceneKit 中的场景和节点

SCNScene 中的节点加入时可以指定一个三维坐标(默认为(x:0, y:0, z:0)),这个坐标是相对于其父节点的位置。这里说明两个概念:

  • 本地坐标系:以场景中的某节点(非根节点)为原点建立的三维坐标系
  • 世界坐标系:以根节点为原点创建的三维坐标系称为世界坐标系。

上图中我们可以看到 NodeA 的坐标是相对于世界坐标系(由于NodeA的父节点是根节点)的位置,而NodeB 的坐标代表了 NodeBNodeA 的本地坐标系位置(NodeB 的父节点是NodeA)。

d、SceneKit 中的摄像机

有了 SCNSceneSCNNode 后,我们还需要一个摄像机(SCNCamera)来决定我们可以看到场景中的哪一块区域(就好比现实世界中有了各种物体,但还需要人的眼睛才能看到物体)。摄像机在 SCNScene 的工作模式如下图:

SceneKit 中的摄像机
  • SceneKitSCNCamera 拍摄的方向始终为 z 轴负方向。
  • 视野(Field of View)是摄像机的可视区域的极限角度。角度越小,视野越窄,反之,角度越大,视野越宽。
  • 视锥体(Viewing Frustum)决定着摄像头可视区域的深度(z 轴表示深度)。任何不在这个区域内的物体将被剪裁掉(离摄像头太近或者太远),不会显示在最终的画面中。

SceneKit中我们可以使用如下方式创建一个摄像机:

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)
e、SCNView

最后,我们需要一个 View 来将 SCNScene 中的内容渲染到显示屏幕上,这个工作由 SCNView 完成。这一步其实很简单,只需要创建一个SCNView 实例,然后将 SCNViewscene属性设置为刚刚创建的 SCNScene,然后将 SCNView 添加到UIKitviewwindow 上即可。示例代码如下:

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

Demo

Demo在我的Github上,欢迎下载。
Multi-MediaDemo

参考文献

iOS计算机视觉—ARKit

相关文章

  • iOS多媒体:AR

    原创:知识探索型文章创作不易,请珍惜,之后会持续更新,不断完善个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈...

  • 增强现实(AR)设计备忘录

    转自:网易UEDC 增强现实(AR)正在改变着我们和外界交互的方式。过去的一些年里,AR技术在多媒体、市场营销、教...

  • 增强现实(AR)设计备忘录

    增强现实(AR)正在改变着我们和外界交互的方式,过去的一些年里,AR技术在多媒体、市场营销、教育、游戏和其他诸多领...

  • iOS百思不得姐、ARKit、旋转动画、立体相册源码等

    iOS精选源码 自定义视图弹出实现方案 仿写百思不得姐 ARKit,距离感应,AR尺子 iOS传感器集锦 AR太阳...

  • iOS demo小集合

    iOS 10.3 切换图标 30DaysofSwift-学习swift的 同上 AR demo AR-集合相关 i...

  • iOS 多媒体

    一、音频播放 1.音效播放(短时间的音频文件) 1> AudioServicesCreateSystemSound...

  • IOS 多媒体

    一、图片 1、UIImageView iOS-视图之UIImageView - 简书 (jianshu.com)[...

  • ARKit初认识

    ARKit 是苹果 WWDC2017 中发布的用于开发iOS平台 AR 功能的框架。AR 全称 Augmented...

  • Beginning iOS AR Game Developmen

    下载地址:Beginning iOS AR Game Development[www.rejoiceblog.co...

  • 苹果又抢先安卓一步?AR游戏登陆iOS 11

    近日苹果正式推送iOS11,很多AR应用也随之上线。iOS11一个很重要的亮点就是AR增强现实,利用它用户可以实现...

网友评论

      本文标题:iOS多媒体:AR

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