ARkit
Introducing ARKit
iOS 11引入ARKit份帐,這是 個(gè)全新的框架讽挟,允許開發(fā)者輕松地為iPhone和iPad創(chuàng)建 與倫比
的增強(qiáng)現(xiàn)實(shí)體驗(yàn)碳胳。通過(guò)將虛擬對(duì)象和虛擬信息同 戶周圍的環(huán)境相互融合,ARKit使得應(yīng) 跳出
屏幕的限制豺鼻,讓它們能夠以全新的 式與現(xiàn)實(shí)世界進(jìn) 交互超燃。
基礎(chǔ)技術(shù)視覺(jué)慣性 程計(jì)
ARKit使 視覺(jué)慣性 程計(jì)(Visual Inertial Odometry, VIO)來(lái)精準(zhǔn)追蹤周圍的世界。VIO將攝像
頭的傳感器數(shù)據(jù)同Core Motion數(shù)據(jù)進(jìn) 融合拘领。這兩種數(shù)據(jù)允許設(shè)備能夠 精度地感測(cè)設(shè)備在房
間內(nèi)的動(dòng)作意乓, 且 需額外校準(zhǔn)。
場(chǎng)景識(shí)別與光亮估
借助ARKit约素,iPhone和iPad可以分析相機(jī)界 中所呈現(xiàn)的場(chǎng)景届良,并在房間當(dāng)中尋找 平 。ARKit不僅可以檢測(cè)諸如桌 和地板之類的 平 圣猎,還可以在較 特征點(diǎn)(feature points)上追蹤
和放置對(duì)象邓深。ARKit還? 攝像頭傳感器來(lái)估算場(chǎng)景當(dāng)中的可 光總亮度,并為虛擬對(duì)象添加符
合環(huán)境照明 的光 量没。
性能硬件與渲染優(yōu)化
ARKit運(yùn) 在Apple A9和A10處 器上梨熙。這些處 器能夠?yàn)锳RKit提供突破性的性能,從 可
以實(shí)現(xiàn)快速場(chǎng)景識(shí)別欠啤,并且還可以讓您基于現(xiàn)實(shí)世界場(chǎng)景荚藻,來(lái)構(gòu)建詳細(xì)并引 注 的虛擬內(nèi)容。
您可以Metal洁段、Scenekit以及諸如Unity应狱、虛幻引擎之類的第三? 具,來(lái)對(duì)ARKit進(jìn) 優(yōu)
化祠丝。
ARKit
ARKit將iOS設(shè)備的攝像頭和設(shè)備動(dòng)作檢測(cè)(Motion)功能疾呻,集成到您的應(yīng) 或者游戲當(dāng)中,從
為 戶提供增強(qiáng)現(xiàn)實(shí)體驗(yàn)写半。
>所謂的增強(qiáng)現(xiàn)實(shí)(Augmented Reality, AR)岸蜗,指的是向設(shè)備攝像頭產(chǎn) 的實(shí)時(shí)動(dòng)態(tài)視圖中,添加2D或者3D元素叠蝇,然后 某種 法讓這些元素看起來(lái)就處于現(xiàn)實(shí)世界當(dāng)中璃岳,所產(chǎn)? 種 戶體
驗(yàn)。ARKit提供 設(shè)備動(dòng)作追蹤、相機(jī)場(chǎng)景捕獲和 級(jí)場(chǎng)景處 矾睦,并讓AR元素的展 變得極為
晦款,從? 簡(jiǎn)化 建立AR戶體驗(yàn)的 作難度。
探索AR的概 枚冗、特性缓溅,以及 解構(gòu)建優(yōu)秀AR場(chǎng)景的最佳實(shí)踐。1.1.ARSession類
這是 個(gè)單,是ARKit的核 類赁温, 于控制設(shè)備攝像頭坛怪,處 傳感器數(shù)據(jù),對(duì)捕獲的圖像進(jìn)
分析等等股囊。
2.ARSessionConfiguration類
跟蹤設(shè)備 向的 個(gè)基本配置,在運(yùn) 時(shí)袜匿,需要指定AR運(yùn) 的配置
ARWorldTrackingSessionConfiguration類
配置跟蹤設(shè)備的 向和位置,以及檢測(cè)設(shè)備攝像頭所看到的現(xiàn)實(shí)世界的表
ARSCNView類
來(lái)增強(qiáng)相機(jī)通過(guò)3D SceneKit所捕捉到的內(nèi)容并展AR效果的 個(gè)view
ARSKView類
來(lái)增強(qiáng)相機(jī)通過(guò)2D SpriteKit所捕捉到的內(nèi)容并展AR效果的 個(gè)view
ARAnchor類
真實(shí)世界的位置和 向,于在 個(gè)AR場(chǎng)景中放置 個(gè)物體
ARPlaneAnchor類
在 個(gè)AR Session會(huì)話中檢測(cè) 個(gè)真實(shí)世界中平 的位置和 向的相關(guān)信息
ARHitTestResult類
在 個(gè)AR Session會(huì)話中通過(guò)檢測(cè)相機(jī)視圖中的 個(gè)點(diǎn)來(lái)獲取真實(shí)世界中表 的相關(guān)信息
ARFrame類
捕獲 個(gè)視頻圖像和位置追蹤信息作為 個(gè)AR會(huì)話的 部分。
ARCamera類
在 個(gè)AR會(huì)話中攝像機(jī)的位置和成像特征信息為捕獲視頻幀
ARLightEstimate類
在 個(gè)AR會(huì)話中估計(jì)場(chǎng)景照明信息關(guān)聯(lián)到 個(gè)捕獲的視頻幀
Understanding Augmented Reality
>探索AR的概 稚疹、特性居灯,以及 解構(gòu)建優(yōu)秀AR場(chǎng)景的最佳實(shí)踐。
對(duì)于所有的AR場(chǎng)景? 内狗,最基本要求是:創(chuàng)建并追蹤現(xiàn)實(shí)空間和虛擬空間之間的關(guān)系怪嫌,其中,
現(xiàn)實(shí)空間是 戶所處的世界柳沙,虛擬空間是可對(duì)可視化內(nèi)容進(jìn) 建模的世界岩灭,這同時(shí)也是ARKit的
基本特征。當(dāng)您的應(yīng) 將這些虛擬內(nèi)容與實(shí)時(shí)視頻結(jié)合赂鲤,并 起顯 的時(shí)候噪径, 戶就可以體驗(yàn)到
所謂的「增強(qiáng)現(xiàn)實(shí)」:您的虛擬內(nèi)容成為 真實(shí)世界的 部分,盡管這只是「錯(cuò)覺(jué)」 已数初。
How World Tracking Works
為 在現(xiàn)實(shí)世界和虛擬世界之間建立對(duì)應(yīng)關(guān)系找爱,ARKit使? 種被稱為視覺(jué)慣性 程計(jì)的技
術(shù)。這項(xiàng)技術(shù)會(huì)將iOS設(shè)備的動(dòng)作感測(cè)硬件信息妙真,加上對(duì)可 場(chǎng)景的計(jì)算機(jī)視覺(jué)分析功能缴允,然后
與設(shè)備的攝像頭相結(jié)合。ARKit將會(huì)去識(shí)別場(chǎng)景圖像當(dāng)中的顯著特征珍德,然后在視頻幀中追蹤這些
特征位置的距離,然后再將這些信息與動(dòng)作感測(cè)數(shù)據(jù)進(jìn) 比較矗漾。從? 成具備設(shè)備位置和動(dòng)作特
征的 精度模型锈候。
全局追蹤(World Tracking)同樣也可以分析和識(shí)別場(chǎng)景當(dāng)中的內(nèi)容。通過(guò)使 點(diǎn)擊測(cè)試(hit-
testing)法(參ARHitTestResult類)敞贡,從 找到與相機(jī)圖像中的某個(gè)點(diǎn)所對(duì)應(yīng)的真實(shí)世界
泵琳。如果您在Session (會(huì)話)配置當(dāng)中啟planeDetection配置的話,那么ARKit就會(huì)去檢測(cè)
相機(jī)圖像當(dāng)中的 平 ,并報(bào)告其位置和? 获列。您可以使 點(diǎn)擊測(cè)試所 成的結(jié)果谷市,或者使 所
檢測(cè)到的 平 ,從 就可以在場(chǎng)景當(dāng)中放置虛擬內(nèi)容击孩,或者與之進(jìn) 交互迫悠。
Best Practices and Limitations
全局追蹤是 項(xiàng)不精確的科學(xué)(inexact science)。盡管在這個(gè)過(guò)程當(dāng)中巩梢,經(jīng)常會(huì)產(chǎn) 可觀的準(zhǔn)確
度创泄,從 讓AR的體驗(yàn) 加真實(shí)。然 括蝠,它嚴(yán)重依賴于設(shè)備物 環(huán)境的相關(guān)細(xì)節(jié)鞠抑, 這些細(xì)節(jié)并
不總是 致,有些時(shí)候也難以實(shí)時(shí)測(cè) 忌警,這也就導(dǎo)致這些物 細(xì)節(jié)往往都會(huì)存在某種程度的錯(cuò)
誤搁拙。要建立 品質(zhì)的AR體驗(yàn),那么請(qǐng)注意下述這些注意事項(xiàng)和提 :
基于可 的照明條件來(lái)設(shè)計(jì)AR場(chǎng)景法绵。全局追蹤涉及到 圖像分析的相關(guān)內(nèi)容感混,因此就需要我們
提供清晰的圖像。如果攝像頭沒(méi)有辦法看到相關(guān)的物 細(xì)節(jié)礼烈,比如說(shuō)攝像頭拍到的是? 空空如
也的墻壁弧满,或者場(chǎng)景的光線實(shí)在太暗的話,那么全局追蹤的質(zhì) 就會(huì)? 降低此熬。
根據(jù)追蹤質(zhì) 的相關(guān)信息來(lái)給 戶進(jìn) 反饋提 庭呜。全局追蹤會(huì)將圖像分析與設(shè)備的動(dòng)作模式關(guān)聯(lián)
起來(lái)。如果設(shè)備正在移動(dòng)的話犀忱,那么ARKit就可以 好地對(duì)場(chǎng)景進(jìn) 建模募谎,這樣即 設(shè)備只是
微晃動(dòng),也不會(huì)影響追蹤質(zhì) 阴汇。但是 旦 戶的動(dòng)作過(guò)多数冬、過(guò)快或者晃動(dòng)過(guò)于激烈,就會(huì)導(dǎo)致圖
像變得模糊搀庶,或者導(dǎo)致視頻幀中要追蹤的特征之間的距離過(guò) 拐纱,從 致使追蹤質(zhì) 的降低。ARCamera類能夠提供追蹤狀態(tài)哥倔,此外還能提供導(dǎo)致該狀態(tài)出現(xiàn)的相關(guān)原因秸架,您可以在UI上展
這些信息,告訴 戶如何解決追蹤質(zhì) 低這個(gè)問(wèn)題咆蒿。
給 平 檢測(cè)預(yù) 點(diǎn)時(shí)間來(lái) 成清晰的結(jié)果东抹, 旦您獲得所需的結(jié)果后蚂子,就禁? 平 檢測(cè)。
開始對(duì) 平 進(jìn) 檢測(cè)的時(shí)候缭黔,所檢測(cè)到的 平 位置和范圍很可能不準(zhǔn)確食茎。不過(guò)隨著時(shí)間的推
移,只要 平 仍然保持在場(chǎng)景當(dāng)中馏谨,那么ARKit就能夠較為精確地估計(jì) 平 的位置和范圍别渔。
當(dāng)場(chǎng)景中有 個(gè)比較 的平坦表 的話,就算您已經(jīng)使 過(guò)這個(gè) 平 來(lái)放置內(nèi)容田巴,那么ARKit可能還會(huì)繼續(xù)對(duì) 平 的錨點(diǎn)位置钠糊、范圍和變換點(diǎn)進(jìn) 修正。
ARSession類
>這是 個(gè)單,是ARKit的核 類壹哺, 于控制設(shè)備攝像頭抄伍,處 傳感器數(shù)據(jù),對(duì)捕獲的圖像進(jìn)
分析等等
每 個(gè)使ARKit創(chuàng)建的AR程必須要有 個(gè)ARSession單 對(duì)象.如果你使ARSCNView或者ARSKView來(lái) 容 的創(chuàng)建AR程的 部分,這個(gè)View已經(jīng)包含? 個(gè)ARSession實(shí).如果你使
編寫的渲染器來(lái)渲染AR內(nèi)容,你必須實(shí) 化和持有 個(gè)ARSession對(duì)象
運(yùn)? 個(gè)會(huì)話必須要有相關(guān)配置:可以實(shí) 化ARSessionConfiguration或者它的 類ARWorldTrackingSessionConfiguration,這些類確定,相對(duì)于現(xiàn)實(shí)世界, ARKit跟蹤設(shè)備的位置和
運(yùn)動(dòng),從 影響您可以創(chuàng)建的基于"增強(qiáng)現(xiàn)實(shí)”技術(shù)的類型
//run法的聲明:
//開始為session在指定的配置和選項(xiàng)下處AR
//configuration個(gè)對(duì)象,定義 會(huì)話的運(yùn)動(dòng)和現(xiàn)場(chǎng)跟蹤 為
//ARSession.RunOptions這是 個(gè)結(jié)構(gòu)體,所以當(dāng)使 系統(tǒng)默認(rèn)的時(shí)候可以寫個(gè)[],當(dāng)你改變它的配置
的時(shí)候,這個(gè)選項(xiàng)會(huì)影響怎么過(guò)渡 個(gè)AR會(huì)話的狀態(tài)
func run(_ configuration: ARSessionConfiguration, options: ARSession.RunOptions
= [])
//pause法的聲明:
func pause()
//代//代? 法可以實(shí)現(xiàn)接收視頻幀圖像捕獲和跟蹤狀態(tài)的AR會(huì)話//個(gè) 法都是可選
var delegate: ARSessionDelegate?
//代 隊(duì),如果沒(méi)有設(shè)置的話,默認(rèn) 主隊(duì)var delegateQueue: DispatchQueue?
//實(shí)現(xiàn)? 的 法可以對(duì)AR會(huì)話的狀態(tài)進(jìn) 改變protocol ARSessionObserver
-顯 和影響AR內(nèi)容
var currentFrame: ARFrame?
func add(anchor: ARAnchor)
func remove(anchor: ARAnchor)
Building a Basic AR Experience構(gòu)建基本的AR場(chǎng)景
配置AR Session管宵,然后使SceneKit或者SpriteKit來(lái)展AR內(nèi)容截珍。
如果您使ARSCNView或者ARSKView類的話,那么ARKit就可? 滿 創(chuàng)建AR場(chǎng)景的基本
要求:即每個(gè)視圖的背景 實(shí)時(shí)的相機(jī)圖像來(lái)展 箩朴,然后還可以渲染您提供的2D或者3D覆蓋
物(overlay)岗喉,從 構(gòu)建出「這些覆蓋物實(shí)際上是位于現(xiàn)實(shí)世界中」這樣 種錯(cuò)覺(jué)。要使 這些視
圖類的話炸庞,您可以根據(jù)您所想要?jiǎng)?chuàng)建的AR場(chǎng)景類型來(lái)進(jìn) 配置钱床,然后為覆蓋物選定位置和表
式。
如果您需要構(gòu)建 定義的視圖來(lái)展AR場(chǎng)景的話埠居,請(qǐng)參閱使Metal來(lái)展AR場(chǎng)景 節(jié)查牌。
本 所涉及的代碼均可以在Xcode項(xiàng) 模板當(dāng)中找到。如果要獲取完整的? 代碼滥壕,請(qǐng)使“Augmented Reality”模板來(lái)創(chuàng)建 個(gè)新的iOS應(yīng) 纸颜,然后在彈出的Content Technology菜單
當(dāng)中選擇SceneKit或者SpriteKit。
Configure and Run the AR Session /配置AR Session并運(yùn)
ARSCNView和ARSKView類都是包含在ARSession當(dāng)中的绎橘,ARSession對(duì)象則 來(lái)管 設(shè)備動(dòng)
作追蹤和進(jìn) 圖像處 的胁孙,也就是創(chuàng)建AR場(chǎng)景的必需品。但是称鳞,要運(yùn)Session涮较,您 先必須
選擇 種Session配置。
您所選擇的配置對(duì)象的類型胡岔,決定 您所創(chuàng)建的AR場(chǎng)景的 格和質(zhì) :
在具備A9或者? 版本處 器的iOS設(shè)備當(dāng)中法希,ARWorldTrackingSessionConfiguration類
提供? 精度的設(shè)備動(dòng)作追蹤功能,可以幫助您將虛擬內(nèi)容「放置」在現(xiàn)實(shí)世界中的某個(gè)表
上靶瘸。
在ARKit所 持的其他設(shè)備當(dāng)中苫亦,ARSessionConfiguration這個(gè)基礎(chǔ)類則提供 基本的動(dòng)作追蹤
功能,可以提供 弱的沉浸式AR體驗(yàn)怨咪。
要啟動(dòng)AR Session屋剑,那么 先要使 您所需要的配置,來(lái)創(chuàng)建Session配置對(duì)象诗眨,然后對(duì)ARSCNView或者ARSKView實(shí) 中的session對(duì)象調(diào)run(_:options:)法:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingSessionConfiguration()
configuration.planeDetection = .horizontal
// Run the view's session
sceneView.session.run(configuration)
}
>重要
>只有當(dāng)視圖即將展 在屏幕的時(shí)候唉匾,才能夠運(yùn) 視圖Session。
當(dāng)您配置完AR Session之后匠楚,就可以使SceneKit或者SpriteKit巍膘,來(lái)將虛擬內(nèi)容放置到視圖當(dāng)
中 。
Providing 3D Virtual Content with SceneKit使SceneKit來(lái)提供3D虛
擬元素
>使SceneKit在您的AR場(chǎng)景中放置逼真的三維圖像芋簿。
由于ARKit會(huì) 動(dòng)將SceneKit空間與現(xiàn)實(shí)世界進(jìn) 匹配峡懈,因此只需要放置 個(gè)虛擬對(duì)象,然后
讓其位于 個(gè)看起來(lái)比較真實(shí)的位置与斤,這就需要您適當(dāng)?shù)卦O(shè)置SceneKit對(duì)象的位置肪康。 如,在
默認(rèn)配置下撩穿,以下代碼會(huì)將 個(gè)10立 厘米的立 體放置在相機(jī)初始位置的前20厘米處:
let cubeNode = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1,
chamferRadius: 0))
cubeNode.position = SCNVector3(0, 0, -0.2) // SceneKit/AR coordinates are in
meters
sceneView.scene.rootNode.addChildNode(cubeNode)
>上述代碼直接在視圖的SceneKit場(chǎng)景中放置? 個(gè)對(duì)象磷支。該對(duì)象會(huì) 動(dòng)追蹤真實(shí)世界的位置,
因?yàn)锳RKit將SceneKit空間與現(xiàn)實(shí)世界空間互相匹配 起來(lái)
此外食寡,您也可以使ARAnchor類來(lái)追蹤現(xiàn)實(shí)世界的位置雾狈,可以? 創(chuàng)建錨點(diǎn)并將其添加到Session當(dāng)中,也可以對(duì)ARKit動(dòng)創(chuàng)建的錨點(diǎn)進(jìn) 觀察(observing)抵皱。 如善榛,當(dāng) 平 檢測(cè)啟
的時(shí)候,ARKit會(huì)為每個(gè)檢測(cè)到的 平 添加錨點(diǎn)叨叙,并保持 新锭弊。要為這些錨點(diǎn)添加可視化內(nèi)容
的話,就需要實(shí)現(xiàn)ARSCNViewDelegate法擂错,如下所 :
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor:
ARAnchor) {
// This visualization covers only detected planes.
guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
// Create a SceneKit plane to visualize the node using its position and
extent.
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height:
CGFloat(planeAnchor.extent.z))
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(planeAnchor.center.x, 0,
planeAnchor.center.z)
// SCNPlanes are vertically oriented in their local coordinate space.
// Rotate it to match the horizontal orientation of the ARPlaneAnchor.
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
// ARKit owns the node corresponding to the anchor, so make the plane a child
node.
node.addChildNode(planeNode)
}
Follow Best Practices for Designing 3D Assets /遵循設(shè)計(jì)3D資源時(shí)的最佳實(shí)踐
>使SceneKit基于物 引擎的照明模型味滞,以 獲得 為逼真的外觀。(參SCNMaterial類和
SceneKit代碼項(xiàng) 當(dāng)中的 「Badger: Advanced Rendering」钮呀。)
打上環(huán)境光遮蔽陰影(Bake ambient occlusion shading)剑鞍,使得物體在各種場(chǎng)景照明條件下能夠
正常亮起。
>如果您打算創(chuàng)建 個(gè)虛擬對(duì)象爽醋,并打算將其放置在AR的真實(shí)平(real-world flat surface)上蚁署,
那么請(qǐng)?jiān)?D素材中的對(duì)象下 ,添加 個(gè)帶有柔和陰影紋 的透明平 蚂四。
Providing 2D Virtual Content with SpriteKit(使SpriteKit來(lái)提供2D虛
擬元素)
使SpriteKit在您的3D AR場(chǎng)景中放置 維圖像光戈。
SpriteKit只包含有2D元素哪痰,但是增強(qiáng)現(xiàn)實(shí)則涉及到現(xiàn)實(shí)世界的3D空間。因此久妆,使ARSKView類來(lái)創(chuàng)建AR場(chǎng)景晌杰,這樣就可以在真實(shí)世界對(duì)應(yīng)的3D位置( ARAnchor對(duì)象)中放置2D精靈元素( SKNode)對(duì)象)。當(dāng) 戶移動(dòng)設(shè)備的時(shí)候筷弦,視圖會(huì) 動(dòng)旋轉(zhuǎn)并縮放與錨點(diǎn)相對(duì)應(yīng)的SpriteKit結(jié)點(diǎn)肋演,看起來(lái)這些元素能夠追蹤相機(jī)所看到的真實(shí)世界。
舉個(gè)? 烂琴,您可以將2D圖像以漂浮的 式爹殊,放置在3D空間當(dāng)中:
// Create a transform with a translation of 0.2 meters in front of the camera.
var translation = matrix_identity_float4x4
translation.columns.3.z = -0.2
let transform = simd_mul(view.session.currentFrame.camera.transform, translation)
// Add a new anchor to the session.
let anchor = ARAnchor(transform: transform)
view.session.add(anchor: anchor)
// (Elsewhere...) Provide a label node to represent the anchor.
func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
return SKLabelNode(text: "??")
}
上 的這個(gè)view(_:nodeFor:)法將會(huì)返回 個(gè)SKLabelNode對(duì)象, 以展? 本標(biāo)簽奸绷。與 多
數(shù)SpriteKit結(jié)點(diǎn) 樣梗夸,這個(gè)類將會(huì)創(chuàng)建 個(gè)2D的可視化表 ,因此ARSKView類將會(huì)以 告牌
的樣式來(lái)展 這個(gè)結(jié)點(diǎn):精靈可以通過(guò)(圍繞z軸)縮放以及旋轉(zhuǎn)健盒,讓其看起來(lái)能夠跟隨錨點(diǎn)的3D位置绒瘦,但是卻始終 向相機(jī)。
Displaying an AR Experience with Metal(使Metal來(lái)展AR場(chǎng)景)通過(guò)渲染相機(jī)圖像扣癣,以及使 位置追蹤信息來(lái)展 覆蓋(overlay)物惰帽,從 來(lái)構(gòu)建 定義的AR視
圖場(chǎng)景。
ARKit中內(nèi)置? 些視圖類父虑,從 能夠輕松地SceneKit或者SpriteKit來(lái)展AR場(chǎng)景该酗。然 ,
如果您使 的是? 的渲染引擎(或者集成 第三 引擎)士嚎,那么ARKit還提供? 定義視圖以
及其他的 持環(huán)境呜魄,來(lái)展AR場(chǎng)景。
在所有的AR場(chǎng)景中莱衩, 先就是要配置 個(gè)ARSession對(duì)象爵嗅, 來(lái)管 攝像頭拍攝和對(duì)設(shè)備動(dòng)作
進(jìn) 處 。Session定義并維護(hù)現(xiàn)實(shí)空間和虛擬空間之間的關(guān)聯(lián)關(guān)系笨蚁,其中睹晒,現(xiàn)實(shí)空間是 戶所
處的世界,虛擬空間是可對(duì)可視化內(nèi)容進(jìn) 建模的世界括细。如果要在 定義視圖當(dāng)中展 您的AR場(chǎng)景的話伪很,那么您需要:
從Session中檢索視頻幀和追蹤信息
將這些幀圖像作為背景,渲染到 定義視圖當(dāng)中
使 追蹤信息奋单,從 在相機(jī)圖像上 定位并繪制AR內(nèi)容
>本 所涉及的代碼均可以在Xcode項(xiàng) 模板當(dāng)中找到锉试。如果要獲取完整的? 代碼,請(qǐng)使“Augmented Reality”模板來(lái)創(chuàng)建 個(gè)新的iOS應(yīng) 览濒,然后在彈出的Content Technology菜單
當(dāng)中選擇“Metal”
Get Video Frames and Tracking Data from the Session(從Session中獲取視頻幀和追
蹤數(shù)據(jù))
請(qǐng)? 創(chuàng)建并維護(hù)ARSession實(shí) 呆盖,然后根據(jù)您所希望提供的AR場(chǎng)景類型拖云,使 合適的Session配置來(lái)運(yùn) 這個(gè)實(shí) 。(要實(shí)現(xiàn)這點(diǎn)的話絮短,請(qǐng)參閱「構(gòu)建基本的AR場(chǎng)景」江兢。)Session從攝像機(jī)當(dāng)中捕獲視頻昨忆,然后在建模的3D空間中追蹤設(shè)備的位置和 向丁频,并提供ARFrame對(duì)
象。每個(gè)ARFrame對(duì)象都包含有單獨(dú)的視頻幀(frame)圖像和被捕獲時(shí)的設(shè)備位置追蹤信息邑贴。
要訪問(wèn)AR Session中 成的ARFrame對(duì)象的話席里,有以下兩種 法,使 何種 法取決于您應(yīng)
的設(shè)計(jì)模式是偏好主動(dòng)拉取(pull)還是被動(dòng)推送(push)拢驾。
如果您傾向于定時(shí)獲取視頻幀的話(也就是主動(dòng)拉取設(shè)計(jì)模式)奖磁,那么請(qǐng)使Session的currentFrame屬性,這樣就可以在每次重繪視圖內(nèi)容的時(shí)候繁疤,獲取當(dāng)前的幀圖像和追蹤信息咖为。ARKit Xcode模板使? 如下 法:
// in Renderer class, called from MTKViewDelegate.draw(in:) via Renderer.update()
func updateGameState() {
guard let currentFrame = session.currentFrame else {
return
}
updateSharedUniforms(frame: currentFrame)
updateAnchors(frame: currentFrame)
updateCapturedImageTextures(frame: currentFrame)
if viewportSizeDidChange {
viewportSizeDidChange = false
updateImagePlane(frame: currentFrame)
}
}
相反,如果您的應(yīng) 設(shè)計(jì)傾向于使 被動(dòng)推送模式的話稠腊,那么請(qǐng)實(shí)現(xiàn)session(_:didUpdate:)代
法躁染,當(dāng)每個(gè)視頻幀被捕獲之后,Session就會(huì)調(diào) 這個(gè)代? 法(默認(rèn)每秒捕獲60幀)架忌。
獲得 個(gè)視頻幀之后吞彤,您就需要繪制相機(jī)圖像 ,然后將AR場(chǎng)景中包含的所有覆蓋物進(jìn)? 新
和展 叹放。
Draw the Camera Image(繪制相機(jī)圖像)
每個(gè)ARFrame對(duì)象的capturedImage屬性都包含 從設(shè)備相機(jī)中捕獲的像素緩沖區(qū)(pixel
buffer)饰恕。要將這個(gè)圖像作為背景繪制到 定義視圖當(dāng)中,您需要從圖像內(nèi)容中構(gòu)建紋(texture)井仰,然后提交使 這些紋 進(jìn)GPU渲染的命令埋嵌。
像素緩沖區(qū)的內(nèi)容將被編碼為雙(biplanar) YCbCr數(shù)據(jù)格式(也成為YUV);要渲染圖像的
話,您需要將這些像素?cái)?shù)據(jù)轉(zhuǎn)換為可繪制的RGB格式俱恶。對(duì)于Metal渲染? 雹嗦,最 效的 法
是使GPU著 代碼(shader code)來(lái)執(zhí) 這個(gè)轉(zhuǎn)換 。借助CVMetalTextureCacheAPI速那,可以
從像素緩沖區(qū)中 成兩個(gè)Metal紋——個(gè) 于決定緩沖區(qū)的亮度(Y)俐银, 個(gè) 于決定緩沖區(qū)的
度(CbCr)。
func updateCapturedImageTextures(frame: ARFrame) {
// Create two textures (Y and CbCr) from the provided frame's captured image//從所提供的視頻幀中端仰,根據(jù)其中所捕獲的圖像捶惜,創(chuàng)建兩個(gè)紋(Y and CbCr)
let pixelBuffer = frame.capturedImage
if (CVPixelBufferGetPlaneCount(pixelBuffer) < 2) {
return
}
capturedImageTextureY = createTexture(fromPixelBuffer: pixelBuffer,
pixelFormat:.r8Unorm, planeIndex:0)!
capturedImageTextureCbCr = createTexture(fromPixelBuffer: pixelBuffer,
pixelFormat:.rg8Unorm, planeIndex:1)!
}
func createTexture(fromPixelBuffer pixelBuffer: CVPixelBuffer, pixelFormat:
MTLPixelFormat, planeIndex: Int) -> MTLTexture? {
var mtlTexture: MTLTexture? = nil
let width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex)
var texture: CVMetalTexture? = nil
let status = CVMetalTextureCacheCreateTextureFromImage(nil,
capturedImageTextureCache, pixelBuffer, nil, pixelFormat, width, height,
planeIndex, &texture)
if status == kCVReturnSuccess {
mtlTexture = CVMetalTextureGetTexture(texture!)
}
return mtlTexture
}
接下來(lái),使 借助顏 變換矩陣將YCbCr轉(zhuǎn)換為RGB的函數(shù)片段荔烧,完成這兩個(gè)紋 的繪制吱七,我
們這 將整個(gè)渲染命令進(jìn) 編碼汽久。
fragment float4 capturedImageFragmentShader(ImageColorInOut in [[stage_in]],
texture2d
capturedImageTextureY [[ texture(kTextureIndexY) ]],
texture2d
capturedImageTextureCbCr [[ texture(kTextureIndexCbCr) ]]) {
constexpr sampler colorSampler(mip_filter::linear,
mag_filter::linear,
min_filter::linear);
const float4x4 ycbcrToRGBTransform = float4x4(
float4(+1.164380f, +1.164380f, +1.164380f, +0.000000f),
float4(+0.000000f, -0.391762f, +2.017230f, +0.000000f),
float4(+1.596030f, -0.812968f, +0.000000f, +0.000000f),
float4(-0.874202f, +0.531668f, -1.085630f, +1.000000f)
);
// Sample Y and CbCr textures to get the YCbCr color at the given texture
coordinate
float4 ycbcr = float4(capturedImageTextureY.sample(colorSampler,
in.texCoord).r,
capturedImageTextureCbCr.sample(colorSampler,
in.texCoord).rg, 1.0);
// Return converted RGB color
return ycbcrToRGBTransform * ycbcr;
}
請(qǐng)使displayTransform(withViewportSize:orientation:)法來(lái)確保整個(gè)相機(jī)圖像完全覆蓋 整
個(gè)視圖。關(guān)于如何使 這個(gè) 法踊餐,以及完整的Metal管道配置代碼景醇,請(qǐng)參閱完整的Xcode模
板。(請(qǐng)使“Augmented Reality”模板來(lái)創(chuàng)建 個(gè)新的iOS應(yīng) 吝岭,然后在彈出的Content
Technology菜單當(dāng)中選擇“Metal”三痰。)
Track and Render Overlay Content(追蹤并渲染覆蓋內(nèi)容)
>AR場(chǎng)景通常側(cè)重于渲染3D覆蓋物,使得這些內(nèi)容似乎是從相機(jī)中所看到的真實(shí)世界的 部分窜管。
為 實(shí)現(xiàn)這種效果散劫,我們使ARAnchor類,來(lái)對(duì)3D內(nèi)容相對(duì)于現(xiàn)實(shí)世界空間的位置和 向進(jìn)
建模幕帆。錨點(diǎn)提供 變換(transform)屬性获搏,在渲染的時(shí)候可供參考。
舉個(gè)? 失乾,當(dāng) 戶點(diǎn)擊屏幕的時(shí)候常熙,Xcode模板會(huì)在設(shè)備前? 約20厘米處,創(chuàng)建 個(gè)錨點(diǎn)碱茁。
func handleTap(gestureRecognize: UITapGestureRecognizer) {
// Create anchor using the camera's current position
if let currentFrame = session.currentFrame {
// Create a transform with a translation of 0.2 meters in front of the
camera
var translation = matrix_identity_float4x4
translation.columns.3.z = -0.2
let transform = simd_mul(currentFrame.camera.transform, translation)
// Add a new anchor to the session
let anchor = ARAnchor(transform: transform)
session.add(anchor: anchor)
}
}
在您的渲染引擎當(dāng)中裸卫,使 每個(gè)ARAnchor對(duì)象的transform屬性來(lái)放置虛擬內(nèi)容。Xcode模板
在內(nèi)部的handleTap法中早芭,使 添加到Session當(dāng)中每個(gè)錨點(diǎn)來(lái)定位 個(gè)簡(jiǎn)單的立 體 格(cube mesh):
func updateAnchors(frame: ARFrame) {
// Update the anchor uniform buffer with transforms of the current frame's
anchors
anchorInstanceCount = min(frame.anchors.count, kMaxAnchorInstanceCount)
var anchorOffset: Int = 0
if anchorInstanceCount == kMaxAnchorInstanceCount {
anchorOffset = max(frame.anchors.count - kMaxAnchorInstanceCount, 0)
}
for index in 0..
let anchor = frame.anchors[index + anchorOffset]
// Flip Z axis to convert geometry from right handed to left handed
var coordinateSpaceTransform = matrix_identity_float4x4
coordinateSpaceTransform.columns.2.z = -1.0
let modelMatrix = simd_mul(anchor.transform, coordinateSpaceTransform)
let anchorUniforms = anchorUniformBufferAddress.assumingMemoryBound(to:
InstanceUniforms.self).advanced(by: index)
anchorUniforms.pointee.modelMatrix = modelMatrix
}
}
在 為復(fù)雜的AR場(chǎng)景中彼城,您可以使 點(diǎn)擊測(cè)試或者 平 檢測(cè),來(lái)尋找真實(shí)世界當(dāng)中曲 的位
置退个。要 解關(guān)于此內(nèi)容的詳細(xì)信息募壕,請(qǐng)參閱planeDetection屬性和hitTest(_:types:)法。對(duì)于這
兩者? 语盈,ARKit都會(huì) 成ARAnchor對(duì)象作為結(jié)果舱馅,因此您仍然需要使 錨點(diǎn)的transform屬
性來(lái)放置虛擬內(nèi)容。
Render with Realistic Lighting(根據(jù)實(shí)際光照度進(jìn) 渲染)
當(dāng)您在場(chǎng)景中配置 于繪制3D內(nèi)容的著 器時(shí)刀荒,請(qǐng)使 每個(gè)ARFrame對(duì)象當(dāng)中的預(yù)計(jì)光照度信
息代嗤,來(lái)產(chǎn)? 為逼真的陰影:
// in Renderer.updateSharedUniforms(frame:):
// Set up lighting for the scene using the ambient intensity if provided
var ambientIntensity: Float = 1.0
if let lightEstimate = frame.lightEstimate {
ambientIntensity = Float(lightEstimate.ambientIntensity) / 1000.0
}
let ambientLightColor: vector_float3 = vector3(0.5, 0.5, 0.5)
uniforms.pointee.ambientLightColor = ambientLightColor * ambientIntensity
要 解該? 中的全部Metal配置,以及所使 的渲染命令缠借,請(qǐng)參 完整的Xcode模板干毅。(請(qǐng)
使“Augmented Reality”模板來(lái)創(chuàng)建 個(gè)新的iOS應(yīng) ,然后在彈出的Content Technology菜單當(dāng)中選擇“Metal”泼返。