說明
ARKit1.5新增功能
- iOS 11.3 上的視訊解析度提升至 1080p,其餘不變;
- 新增豎直平面識別
ARWorldTrackingConfiguration.PlaneDetection
; - 新增
ARPlaneAnchor
中粗略平面估計,見ARPlaneAnchor; - 新增
ARSession.setWorldOrigin
方法可以重新設定世界座標原點; - 新增圖片識別能力,示例程式碼見Recognizing Images in an AR Experience
ARsession
被打斷後,可嘗試恢復追蹤.詳見sessionShouldAttemptRelocalization
代理方法;
還有一個增強功能:
- 打了斷點,再恢復後,
session
的VIO(視覺慣性里程計)也會繼續工作了.原來放置在世界座標系中的虛擬物體仍然是可見的.
圖片識別
這個功能使用起來其實非常簡單,AR功能啟動時設定要識別的圖片,然後在回撥方法中處理識別到的錨點就可以了.
// 載入要識別的圖片組
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
fatalError("Missing expected asset catalog resources.")
}
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = referenceImages //設定識別項
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
複製程式碼
// MARK: - ARSCNViewDelegate (Image detection results)
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
// 判斷識別到的錨點型別
guard let imageAnchor = anchor as? ARImageAnchor else { return }
let referenceImage = imageAnchor.referenceImage //獲取錨點對應的圖片
updateQueue.async {
// 建立一個平面來顯示檢測到的圖片(與圖片相同大小)
let plane = SCNPlane(width: referenceImage.physicalSize.width,
height: referenceImage.physicalSize.height)
let planeNode = SCNNode(geometry: plane)
planeNode.opacity = 0.25
/*
`SCNPlane`在它的本地座標系是豎直的, 但`ARImageAnchor`會假設圖片在自身本地座標系中是水平的,所以要旋轉平面.
*/
planeNode.eulerAngles.x = -.pi / 2
/*
圖片錨點在初始化後是不再被追蹤的,所以建立一個動畫效果以顯示平面出現了.
*/
planeNode.runAction(self.imageHighlightAction)
// 新增到場景中
node.addChildNode(planeNode)
}
}
// 高亮動畫
var imageHighlightAction: SCNAction {
return .sequence([
.wait(duration: 0.25),
.fadeOpacity(to: 0.85, duration: 0.25),
.fadeOpacity(to: 0.15, duration: 0.25),
.fadeOpacity(to: 0.85, duration: 0.25),
.fadeOut(duration: 0.5),
.removeFromParentNode()
])
}
複製程式碼
參考圖片referenceImages
參考圖片就是要被識別的圖片,需要放置在Xcode的素材資料夾asset catalog中:
- 開啟專案的
asset catalog
,點選新增按鈕(+)來新增新的AR資源組; - 從
Finder
中拖拽圖片到資源組中; - 需要在檢查器中給每張圖片指定一個物理尺寸,還可以設定一個描述性的名字(可選);
注意圖片識別的能力: 需要精心挑選,設計,配置圖片來達到更好的可靠性和效能表現:
- 圖片的物理尺寸設定應儘可能精確.ARKit需要根據這個值來確定真實世界中的圖片到相機的距離,設定不當會導致
ARImageAnchor
到相機的距離出錯; - 當向Xcode的素材資料夾asset catalog新增圖片時,應注意Xcode提供的圖片質量預估警告.高對比度的圖片在圖片識別中效果最好;
- 使用平面圖片來檢測.如果要識別的圖片不是平面的,比如是酒瓶上的標籤,那ARKit可能不會識別或者給出錯誤的錨點位置;
- 考慮你的圖片在不同光照下的表現.如果圖片是列印在光滑的紙上或者顯示在螢幕上,這些平面上的反光可能會妨礙識別;
應用最佳實踐
使用識別出的圖片作為AR場景的參照系.使用識別出的圖片來錨定虛擬場景,而不是再讓使用者選擇場景的擺放位置,或直接粗暴地擺放在使用者的場景中.你甚至可以使用多個識別圖片.例如,一個給零售店用的app,可以通過識別貼在門兩側的海報(門左邊一個海報貼圖,右邊一個)來算出門的位置,從而建立出一個虛擬角色並從門中走出來.
注意:可以使用
ARSession setWorldOrigin(relativeTransform:)
方法來重設世界座標系,這樣就可以放置所有錨點和其他相關內容到你選擇的參考點上.
設計AR流程,將識別出的圖片作為虛擬內容的起始點.ARKit不會再追蹤已探測到的圖片的位置和朝向.如果你試圖讓虛擬內容一直緊貼在識別出的圖片上,那麼可能會顯示不正確.應該做的是,使用識別出的圖片作為參照系,來開始一個動態場景.例如你的app需要識別出科幻電影的海報,然後會有幾個太空船從海報中飛出來,並飛到周圍環境中去.
考慮好何時允許圖片檢測以觸發(或重複)AR互動.對於配置session configuration中的detectionImages
陣列中的每張參考圖片,ARKit都只會新增一個圖片錨點.如果你的AR流程中向一個識別出的圖片新增了虛擬內容,那這個動作預設情況下只會發生一次.要想再體驗一次這個流程,可以呼叫session的remove(anchor:)
方法來移除對應的ARImageAnchor
.移除該錨點之後,ARKit會在下次識別出圖片後,再新增一個新的錨點.
例如,還是前面科幻電影海報的例子,當第一次的動畫正在播放時,太空船正從電影海報中飛出來時,你肯定不想要再出現一個同樣的.要等到動畫播放完成後再移除錨點,這樣當使用者再對準海報時,就可以再觸發一次動畫.
ARReferenceImage的建立
除了前面講到的ARReferenceImage.referenceImages(inGroupNamed:bundle:)
方法可以從素材中載入圖片作為參考圖片外,還有另外兩個建立方法:
- (instancetype)initWithCGImage:(CGImageRef)image orientation:(CGImagePropertyOrientation)orientation physicalWidth:(CGFloat)physicalWidth;
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer orientation:(CGImagePropertyOrientation)orientation physicalWidth:(CGFloat)physicalWidth;
複製程式碼
這兩種方法可以分別從CGImageRef
和CVPixelBufferRef
中建立參考圖片,這樣就靈活多了.