前言
對(duì)ARKit感興趣的同學(xué),可以訂閱ARKit教程專題
源代碼地址在這里
正文
在本章中,我們將了解AR session是什么以及如何管理它。這包括啟動(dòng),停止和重置。還將學(xué)習(xí)如何處理會(huì)話錯(cuò)誤并跟蹤典型AR應(yīng)用程序生命周期中可能發(fā)生的問題。
準(zhǔn)備工作
我們需要在上一個(gè)項(xiàng)目的基礎(chǔ)之上添加一些可交互的事件,我們需要在ViewController.swift添加一些UI控件和一些事件方法:
// MARK: - Outlets
@IBOutlet var sceneView: ARSCNView!
@IBOutlet weak var statusLabel: UILabel!
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var styleButton: UIButton!
@IBOutlet weak var resetButton: UIButton!
// MARK: - Actions
@IBAction func startButtonPressed(_ sender: Any) {
}
@IBAction func styleButtonPressed(_ sender: Any) {
}
@IBAction func resetButtonPressed(_ sender: Any) {
}

創(chuàng)建一個(gè) AR session
我們之前在Main.storyboard中添加的ARSCNView是一個(gè)很基本的SceneKit view。它包括一個(gè)ARSession對(duì)象,該對(duì)象負(fù)責(zé)處理ARKit的運(yùn)動(dòng)追蹤和圖像處理工作。需要注意的是,ARSession對(duì)象是基于會(huì)話來(lái)進(jìn)行工作的,也就是說(shuō),你需要先創(chuàng)建一個(gè)AR session實(shí)例,然后運(yùn)行它,才可以啟動(dòng)AR的追蹤過程。
創(chuàng)建con?guration
在啟動(dòng)AR session,之前,必須創(chuàng)建AR session con?guration (AR 會(huì)話配置)。此配置用于在真實(shí)世界(設(shè)備所在的位置)和虛擬 3D 世界(虛擬內(nèi)容所在的位置)之間建立連接。
有兩種類型的配置:
- AROrientationTrackingConfiguration, 用于三個(gè)自由度跟蹤, 簡(jiǎn)稱3DOF。
- ARWorldTrackingConfiguration,用于六個(gè)自由度跟蹤, 簡(jiǎn)稱 6DOF。
3DOF
3DOF跟蹤設(shè)備旋轉(zhuǎn),分為Pitch(俯仰)、Roll(滾動(dòng))和 Yaw(偏航) 組件,表示圍繞X 軸、Y 軸和 Z 軸的旋轉(zhuǎn)。這由 AR 定向跟蹤配置會(huì)話配置類型支持。
6DOF
6DOF 跟蹤Pitch、Roll和 Yaw,類似于 3DOF。它還使用 Sway、Heave 和 Surge 組件跟蹤 3D 空間中的設(shè)備移動(dòng)。這些新組件表示與 X 軸、Y 軸和 Z 軸平行的移動(dòng)。這由 ARWorldTrack 配置會(huì)話配置類型支持。

檢查設(shè)備功能
您正在創(chuàng)建 AR 應(yīng)用程序需要 6DF 跟蹤,因此你將使用 ARWorldTrackingConfiguration對(duì)象。良好的編碼實(shí)踐是檢查設(shè)備是否能夠支持此功能。
為此,在 initARSession() 中添加以下內(nèi)容:
guard ARWorldTrackingConfiguration.isSupported else { print("*** ARConfig: AR World Tracking Not Supported") return }
可以使用 類的isSupported屬性來(lái)檢查設(shè)備是否支持該配置。如果不是,這是一個(gè)偉大的地方,通知用戶適當(dāng)?shù)南?。以機(jī)智的方式向用戶提供壞消息總是一個(gè)好主意。
現(xiàn)在您知道設(shè)備支持 6DOF,可以創(chuàng)建配置對(duì)象。
將以下內(nèi)容添加到 initARSession() 的底部:
// 1
let config = ARWorldTrackingConfiguration()
// 2
config.worldAlignment = .gravity
// 3
config.providesAudioData = false
上面的代碼主要功能如下:
- 首先,創(chuàng)建一個(gè) ARWorldTrackingConfiguration配置實(shí)例, 該實(shí)例已分配給config。
- 設(shè)置worldAlignment屬性,用于指定虛擬內(nèi)容與真實(shí)世界的關(guān)系。這里有三個(gè)選項(xiàng):
?a) gravity: 這將設(shè)置虛擬內(nèi)容坐標(biāo)系的 Y 軸,與地球引力平行。這可確保 Y 軸始終在實(shí)際空間中向上指向。它還使用設(shè)備的初始位置作為坐標(biāo)系源,稱為世界原點(diǎn)。這是 AR 會(huì)話開始時(shí)設(shè)備在真實(shí)世界中的位置。
?b) gravityAndHeading:這還會(huì)設(shè)置虛擬內(nèi)容坐標(biāo)系的 Y 軸,與重力平行。它還定向 X 軸,使其從西向東運(yùn)行,并且 Z 軸,以便從北到南運(yùn)行:
?最后,它還使用設(shè)備的初始位置作為世界起源。例如,你可以使用它將用戶指向真實(shí)世界的指南針方向。
?c)camera:這將使用設(shè)備方向和 3D 空間中的位置作為世界原點(diǎn)。例如,用戶可以在啟動(dòng) AR 會(huì)話之前將其設(shè)備放在墻上。
- 設(shè)置worldAlignment屬性,用于指定虛擬內(nèi)容與真實(shí)世界的關(guān)系。這里有三個(gè)選項(xiàng):
- 通過將providesAudioData設(shè)置為false來(lái)禁用該功能。此屬性允許 AR 會(huì)話捕獲音頻。
- 這里還有一個(gè)其他的屬性,isLightEstimationEnabled。在后面的章節(jié)中你會(huì)了解它的。
運(yùn)行session
現(xiàn)在已經(jīng)創(chuàng)建了 AR 配置,剩下的唯一事情就是啟動(dòng) AR 會(huì)話。
在 initARSession() 方法中添加以下內(nèi)容:
sceneView.session.run(config)
在 ARSCNView 的 ARSession 上調(diào)用run(_:options:),傳入剛剛創(chuàng)建的 ARWorldTrackingConfiguration。就是這個(gè),你的AR session現(xiàn)在啟動(dòng)并運(yùn)行,并且它正在積極收集6DOF跟蹤數(shù)據(jù)。
操控AR session
盡管 AR session已啟動(dòng)并運(yùn)行,但它不是你可以啟動(dòng)和忽略的內(nèi)容??赡苄枰鶕?jù)應(yīng)用中發(fā)生的情況控制其行為。 其實(shí),控制 AR session是非常簡(jiǎn)單的。
Pausing:ARSession.pause()暫停AR session追蹤。在用戶切換到另一個(gè)應(yīng)用程序時(shí),可以很好地使用會(huì)話。
Resuming: ARSession.run() 將恢復(fù)暫停的會(huì)話。它將利用現(xiàn)有的跟蹤配置來(lái)恢復(fù)追蹤過程。
Updating: ARSession.run(ARSessionConfig)用于更新對(duì)配置的更改。也許你確實(shí)希望啟用音頻采樣,但僅當(dāng)用戶按下按鈕時(shí)。首先從活動(dòng)運(yùn)行的會(huì)話獲取配置,調(diào)整其屬性,然后使用已更改的配置重新運(yùn)行會(huì)話。
Resetting: ARSession.run(_:options:)在異常情況下很有用,并且別無(wú)選擇,只能重新啟動(dòng) AR session。有可能用戶長(zhǎng)時(shí)間關(guān)閉設(shè)備,這將使任何以前收集的跟蹤信息毫無(wú)意義。
更新狀態(tài)信息
我們可以把AR session的實(shí)時(shí)狀態(tài)顯示到屏幕上,我們可以添加一個(gè)對(duì)象:var trackingStatus: String = ""。然后添加如下代碼:
func renderer(_ renderer: SCNSceneRenderer,
updateAtTime time: TimeInterval) {
DispatchQueue.main.async {
self.statusLabel.text = self.trackingStatus
}
}
AR session錯(cuò)誤處理
我們可以通過ARSessionDelegate來(lái)得知AR session的一些問題。
@protocol ARSessionDelegate <ARSessionObserver>

我們可以作如下操作:
extension ViewController : ARSCNViewDelegate {
// MARK: - SceneKit Management
func renderer(_ renderer: SCNSceneRenderer,
updateAtTime time: TimeInterval) {
DispatchQueue.main.async {
self.statusLabel.text = self.trackingStatus
}
}
// MARK: - Session State Management
func session(_ session: ARSession,
cameraDidChangeTrackingState camera: ARCamera) {
switch camera.trackingState {
// 1
case .notAvailable:
trackingStatus = "Tacking: Not available!"
// 2
case .normal:
trackingStatus = "Tracking: All Good!"
// 3
case .limited(let reason):
switch reason {
case .excessiveMotion:
trackingStatus = "Tracking: Limited due to excessive motion!"
// 3.1
case .insufficientFeatures:
trackingStatus = "Tracking: Limited due to insufficient features!"
// 3.2
case .initializing:
trackingStatus = "Tracking: Initializing..."
// 3.3
case .relocalizing:
trackingStatus = "Tracking: Relocalizing..."
}
}
}
// MARK: - Session Error Managent
func session(_ session: ARSession,
didFailWithError error: Error) {
trackingStatus = "AR Session Failure: \(error)"
}
func sessionWasInterrupted(_ session: ARSession) {
trackingStatus = "AR Session Was Interrupted!"
}
func sessionInterruptionEnded(_ session: ARSession) {
trackingStatus = "AR Session Interruption Ended"
}
// MARK: - Plane Management
}
想必大部分的代碼你們可以看得很明白,不過需要解釋的是ARCamera.trackingStatus:
- notAvailable: 由于不可預(yù)見的原因,AR session無(wú)法跟蹤。在這種情況下,你沒有什么可以做的,只是希望狀態(tài)改變到更可控的狀態(tài)。
- normal: AR session 處于正常狀態(tài)。
顯示Debug選項(xiàng)
顯示Debug選項(xiàng)也不難,sceneView有一個(gè)debugOptions選項(xiàng),該選項(xiàng)決定了你想要顯示哪些Debug信息。
sceneView.debugOptions = []
下面是相關(guān)的文檔信息:
public struct SCNDebugOptions : OptionSet {
public init(rawValue: UInt)
public static var showPhysicsShapes: SCNDebugOptions { get } //show physics shape
public static var showBoundingBoxes: SCNDebugOptions { get } //show object bounding boxes
public static var showLightInfluences: SCNDebugOptions { get } //show objects's light influences
public static var showLightExtents: SCNDebugOptions { get } //show light extents
public static var showPhysicsFields: SCNDebugOptions { get } //show SCNPhysicsFields forces and extents
public static var showWireframe: SCNDebugOptions { get } //show wireframe on top of objects
@available(iOS 11.0, *)
public static var renderAsWireframe: SCNDebugOptions { get } //render objects as wireframe
@available(iOS 11.0, *)
public static var showSkeletons: SCNDebugOptions { get } //show skinning bones
@available(iOS 11.0, *)
public static var showCreases: SCNDebugOptions { get } //show subdivision creases
@available(iOS 11.0, *)
public static var showConstraints: SCNDebugOptions { get } //show slider constraint
@available(iOS 11.0, *)
public static var showCameras: SCNDebugOptions { get } //show cameras
}
你們可以自己試著加一下。例如,我們做如下設(shè)置:
sceneView.debugOptions = [
SCNDebugOptions.showFeaturePoints,
SCNDebugOptions.showWorldOrigin,
SCNDebugOptions.showBoundingBoxes,
SCNDebugOptions.showWireframe
]
呈現(xiàn)的效果如下:

Feature points: 這些是你整個(gè)場(chǎng)景中看到的小點(diǎn);它們代表了 ARKit 在攝像機(jī)圖像中檢測(cè)到的顯著功能,這些功能又用作地標(biāo),以在設(shè)備移動(dòng)時(shí)準(zhǔn)確跟蹤設(shè)備的位置和方向。
World origin: 這是紅色、綠色和藍(lán)色線的大交叉點(diǎn),位于開始AR session的位置。紅線表示正 X 軸,綠線表示正 Y 軸,藍(lán)線表示正 Z 軸。
Bounding boxes: 這些是所有 3D 對(duì)象周圍的框狀輪廓。
Wireframe: 需要注意的是,你現(xiàn)在可以在 AR 場(chǎng)景中每個(gè) 3D 對(duì)象的曲面上看到多邊形的輪廓。你可以精確查看這些幾何形狀的詳細(xì)程度。
| 上一章 | 目錄 | 下一章 |
|---|