點擊獲取本文示例代碼, 本文代碼在分支ARKit中。
如果你想了解更多關于OpenGL ES的知識,請移步至OpenGL ES相關文章目錄
iOS11推出了新框架ARKit,通過ARKit和SceneKit可以很方便的制作AR App。蘋果也提供了AR基本的應用框架,你可以直接從此開始你的AR App的開發(fā)。

不過本系列文章將使用OpenGL ES為ARKit提供渲染支持,接下來我們先去了解一下ARKit的理論相關知識。
AR基本概念
AR最基本的概念就是將虛擬的計算機圖形和真實環(huán)境結合的技術。該技術有很多種實現(xiàn)方式。
- 使用2D或者3D圖形裝飾人臉,常見于一些相機和視頻類App,主要使用人臉識別追蹤技術。
- 基于標記的3D模型放置,比如基于AR的故事書,陰陽師的現(xiàn)世召喚。標記可以是簡單的黑框包裹的標記,也可以是一張復雜圖片的特征點訓練數(shù)據(jù)。如果你感興趣可以前往ARToolKit,這是一個開源的AR框架,主要用于基于標記的AR。最近出ARToolkit6 Beta了,不知道有沒有新的功能開放。
- 追蹤真實環(huán)境的特征點,計算真實攝像機在真實環(huán)境的位置。所謂特征點,就是圖片中灰度變化比較劇烈的位置,所以想要更精準穩(wěn)定的計算,就需要真實環(huán)境的顏色變化比較豐富。ARKit就是使用這種原理進行攝像機定位的。
世界追蹤(WorldTracking)
通過追蹤真實世界的特征點,計算真實攝像機位置并應用到3D世界的虛擬攝像機是AR實現(xiàn)中最重要的部分。計算結果的精確性直接影響到渲染出來的結果。ARKit使用ARSession來管理整個AR處理流程,包括攝像機位置的計算。
#pragma make - AR Control
- (void)setupAR {
if (@available(iOS 11.0, *)) {
self.arSession = [ARSession new];
self.arSession.delegate = self;
}
}
- (void)runAR {
if (@available(iOS 11.0, *)) {
ARWorldTrackingSessionConfiguration *config = [ARWorldTrackingSessionConfiguration new];
config.planeDetection = ARPlaneDetectionHorizontal;
[self.arSession runWithConfiguration:config];
}
}
- (void)pauseAR {
if (@available(iOS 11.0, *)) {
[self.arSession pause];
}
}
使用ARSession的方式很簡單,初始化,設置delegate,開啟ARSession需要傳入一個配置ARWorldTrackingSessionConfiguration,ARWorldTrackingSessionConfiguration代表AR系統(tǒng)會追蹤真實世界的特征點,計算攝像機位置。蘋果以后也有可能會出ARMarkerTrackingSessionConfiguration之類用來識別追蹤標記的配置吧。ARSession開啟后會啟動相機,并且會通過傳感器感知手機位置。借用WWDC中的一張圖。

ARSession綜合相機捕獲的視頻流和位置信息生成一系列連續(xù)的ARFrame。
- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame {
...
}
每個ARFrame包含了從相機捕捉的圖片,相機位置相關信息等。在這個方法里我們需要繪制相機捕捉的圖片。根據(jù)相機位置等信息繪制3D物體等。
平面檢測
ARKit提供了另一個很酷的功能,檢測真實世界的平面,并提供一個ARPlaneAnchor對象描述平面的位置,大小,方向等信息。
- (void)runAR {
if (@available(iOS 11.0, *)) {
ARWorldTrackingSessionConfiguration *config = [ARWorldTrackingSessionConfiguration new];
config.planeDetection = ARPlaneDetectionHorizontal;
[self.arSession runWithConfiguration:config];
}
}
上面的config.planeDetection = ARPlaneDetectionHorizontal;設置了檢測平面的類型是水平。不過目前也就只有這一個選項可以選。如果ARKit檢測到了平面,會通過delegate中的方法- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor*>*)anchors提供數(shù)據(jù)給你。你可以判斷ARAnchor是不是ARPlaneAnchor來判斷是否檢測到了平面。ARAnchor用來表示3D物體在真實環(huán)境的位置。你只要保持你的3D物體和ARAnchor的3D變換同步就能實現(xiàn)AR效果了。
Hit Test
Hit Test可以讓你方便的在檢測到的平面上放置物體。當你點擊屏幕時,使用Hit Test可以檢測出你點擊的位置有哪些平面,并且提供ARAnchor用于設置放置物體的位置。
[frame hitTest:CGPointMake(0.5, 0.5) types:ARHitTestResultTypeExistingPlane];
使用ARFrame的hitTest方法,第一個傳入的點取值范圍從(0,0)到(1,1),第二個參數(shù)代表可以檢測哪些對象??梢詸z測到的對象如下。
-
ARHitTestResultTypeFeaturePoint,根據(jù)距離最近的特征點檢測出來的連續(xù)表面。 -
ARHitTestResultTypeEstimatedHorizontalPlane,非精準方式計算出來與重力垂直的平面。 -
ARHitTestResultTypeExistingPlane, 已經(jīng)檢測出來的平面,檢測時忽略平面本身大小,把它看做一個無窮大的平面。 -
ARHitTestResultTypeExistingPlaneUsingExtent, 已經(jīng)檢測出來的平面,檢測時考慮平面本身的大小。
檢測成功則返回NSArray<ARHitTestResult *> *,ARHitTestResult中包含檢測類型,相交點的距離,平面的ARAnchor。注意只有檢測到ARHitTestResultTypeExistingPlane和ARHitTestResultTypeExistingPlaneUsingExtent才會有ARAnchor。這四個檢測類型是可以通過|的方式同時存在的,比如ARHitTestResultTypeEstimatedHorizontalPlane | ARHitTestResultTypeExistingPlane。
光線強度調節(jié)
ARKit還提供了一個檢測光照強度的功能,主要為了讓3D模型的光照和環(huán)境的光照強度保持一致。在ARFrame中有一個lightEstimate的變量,如果檢測光照強度成功,則會有值。值的類型為ARLightEstimate,其中只包含一個變量ambientIntensity。在3D光照模型中,它對應環(huán)境光,它的值從0 ~ 2000。使用OpenGL渲染時,可以使用這個值調整光照模型中的環(huán)境光強度。
ARKit的理論知識差不多到此結束了,下一篇將會介紹如何使用OpenGL ES渲染ARFrame里的內(nèi)容。