版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.09.27 |
前言
蘋果最近新出的一個API就是ARKit,是在2017年6月6日,蘋果發布iOS11系統所新增框架,它能夠幫助我們以最簡單快捷的方式實現AR技術功能。接下來幾篇我們就詳細的對ARKit框架進行詳細的解析。AR相關代碼已經上傳到Github - 刀客傳奇,感興趣的可以看上面幾篇。
1. ARKit框架詳細解析(一)—— 基本概覽
2. ARKit框架詳細解析(二)—— 關于增強現實和ARKit
3. ARKit框架詳細解析(三)—— 開啟你的第一個AR體驗之旅
4. ARKit框架詳細解析(四)—— 處理增強現實中的3D交互和UI控件
創建基于面部的AR體驗
放置和動畫3D用戶臉部的內容,并匹配面部表情(在具有兼容的前置攝像頭的設備上)。
概要
此示例應用程序提供了一個簡單的界面,允許您使用兼容設備上的前置攝像頭在四個增強現實(AR)可視化之間進行選擇(請iOS Device Compatibility Reference)。
- 單獨的相機視圖,沒有任何AR內容。
- ARKit提供的面部網格,可以自動估計真實的定向照明環境。
- 虛擬3D內容似乎附加到用戶的真實面孔(并被部分遮蔽)。
- 一個簡單的機器人角色,其表情符合用戶的動畫。
使用示例應用程序中的“+”按鈕在這些模式之間切換,如下所示。
Start a Face Tracking Session in a SceneKit View - 在SceneKit視圖中啟動面部跟蹤會話
像ARKit的其他用途一樣,臉部跟蹤需要配置和運行會話(ARSession對象),并將視頻圖像與虛擬內容一起渲染。 有關會話和視圖設置的更詳細說明,請參閱About Augmented Reality and ARKit 和 Building Your First AR Experience。 此示例使用SceneKit顯示AR體驗,但也可以使用SpriteKit或使用Metal構建您自己的渲染器(請參閱ARSKView 和 Displaying an AR Experience with Metal)。
面部跟蹤與用于配置會話的類中的ARKit的其他用途不同。 要啟用臉部跟蹤,請創建一個實例,配置其屬性,并將其傳遞給與視圖關聯的AR會話的方法,如下所示。
guard ARFaceTrackingConfiguration.isSupported else { return }
let configuration = ARFaceTrackingConfiguration()
configuration.isLightEstimationEnabled = true
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
在提供需要面部跟蹤AR會話的用戶功能之前,請先檢查.
屬性來確定當前設備是否支持ARKit的臉部跟蹤。
Track the Position and Orientation of a Face - 跟蹤面部的位置和方向
當臉部跟蹤處于活動狀態時,ARKit會自動將對象添加到正在運行的AR會話中,其中包含有關用戶臉部的信息,包括其位置和方向。
注意:ARKit會檢測并提供有關用戶臉部信息的信息。 如果攝像機圖像中存在多個面部,則ARKit會選擇最大或最清晰可識別的臉部。
在基于SceneKit的AR體驗中,您可以在方法(從協議)中添加與面錨相對應的3D內容。 ARKit為錨點添加了一個SceneKit節點,并更新了每一幀上節點的位置和方向,因此您添加到該節點的任何SceneKit
內容都會自動跟隨用戶臉部的位置和方向。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
// Hold onto the `faceNode` so that the session does not need to be restarted when switching masks.
faceNode = node
serialQueue.async {
self.setupFaceNodeContent()
}
}
在此示例中,該方法調用setupFaceNodeContent
方法將SceneKit內容添加到faceNode
。 例如,如果您更改示例代碼中的showsCoordinateOrigin
變量,則應用程序將x / y / z軸的可視化添加到該節點,指示面部錨點坐標系的起點。
Use Face Geometry to Model the User’s Face - 使用面幾何來建模用戶臉部
ARKit提供與用戶臉部的大小,形狀,拓撲和當前面部表情相匹配的粗略3D網格幾何。 ARKit還提供了該類,提供了一種在SceneKit中可視化此網格的簡單方法。
您的AR體驗可以使用此網格放置或繪制似乎附加到臉部的內容。 例如,通過將半透明紋理應用于此幾何體,您可以將虛擬紋身或化妝畫到用戶的皮膚上。
要創建一個SceneKit面幾何,使用SceneKit視圖用于呈現的Metal設備初始化一個對象:
// This relies on the earlier check of `ARFaceTrackingConfiguration.isSupported`.
let device = sceneView.device!
let maskGeometry = ARSCNFaceGeometry(device: device)!
示例代碼的setupFaceNodeContent
方法(如上所述)將包含面幾何的節點添加到場景中。 通過使該節點成為由臉部錨點提供的節點的子節點,臉部模型自動跟蹤用戶臉部的位置和方向。
為了使屏幕上的臉部模型符合用戶臉部的形狀,即使用戶眨眼,說話并進行各種面部表情,您需要在委托回調中檢索更新的臉部網格。
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
virtualFaceNode?.update(withFaceAnchor: faceAnchor)
}
然后,通過將新的面網格傳遞給其方法來更新場景中的對象進行匹配:
func update(withFaceAnchor anchor: ARFaceAnchor) {
let faceGeometry = geometry as! ARSCNFaceGeometry
faceGeometry.update(from: anchor.geometry)
}
Place 3D Content on the User’s Face - 將3D內容放在用戶臉上
ARKit提供的面部網格的另一個用途是在場景中創建遮擋幾何。 遮擋幾何是不會呈現任何可見內容(允許相機圖像顯示)的3D模型,但會阻礙相機對場景中其他虛擬內容的視圖。
這種技術創造出真實面對與虛擬對象交互的錯覺,即使臉部是2D攝像機圖像,虛擬內容是渲染的3D對象。 例如,如果您將遮擋幾何圖形和虛擬眼鏡放置在用戶的臉部上,則臉部可能會遮擋眼鏡框架。
要創建面部的遮擋幾何,請先創建一個對象,如上例所示。 但是,不要使用可見的外觀來配置該對象的SceneKit材質,而是在渲染期間將材質設置為渲染深度而不是顏色:
geometry.firstMaterial!.colorBufferWriteMask = []
occlusionNode = SCNNode(geometry: geometry)
occlusionNode.renderingOrder = -1
因為材料渲染深度,所以SceneKit渲染的其他對象正確地出現在它的前面或后面。 但是由于材質不會呈現顏色,相機圖像會出現在其位置。 示例應用程序將此技術與位于用戶眼睛前方的SceneKit對象相結合,創建一個效果,其中對象被用戶的鼻子實際遮蔽。
Animate a Character with Blend Shapes - 用混合形狀動畫化一個人物
除了上述示例中所示的面部網格之外,ARKit還提供了一種以詞典形式的用戶面部表情的更抽象的模型。 您可以使用該字典中的命名系數值來控制自己的2D或3D資產的動畫參數,創建遵循用戶真實面部動作和表達的角色(如頭像或木偶)。
作為混合形狀動畫的基本演示,此示例包含使用SceneKit原始形狀創建的機器人角色頭部的簡單模型。 (請參閱源代碼中的robotHead.scn
文件。)
要獲取用戶當前的面部表情,請從代理回調中的面部錨點中讀取字典:
func update(withFaceAnchor faceAnchor: ARFaceAnchor) {
blendShapes = faceAnchor.blendShapes
}
然后,檢查該字典中的鍵值對以計算模型的動畫參數。 有52個獨特系數。 您的應用程序可以使用盡可能少的或很多的必要條件來創建您想要的藝術效果。 在該示例中,RobotHead
類執行此計算,將參數映射到機器人眼睛因子的一個軸,以及偏移機器人下顎位置的參數。
var blendShapes: [ARFaceAnchor.BlendShapeLocation: Any] = [:] {
didSet {
guard let eyeBlinkLeft = blendShapes[.eyeBlinkLeft] as? Float,
let eyeBlinkRight = blendShapes[.eyeBlinkRight] as? Float,
let jawOpen = blendShapes[.jawOpen] as? Float
else { return }
eyeLeftNode.scale.z = 1 - eyeBlinkLeft
eyeRightNode.scale.z = 1 - eyeBlinkRight
jawNode.position.y = originalJawY - jawHeight * jawOpen
}
}
后記
未完,待續~~~~