基于ARKit的開發(fā)

ARKit是蘋果在WWDC2017推出的一個(gè)用于實(shí)現(xiàn)增強(qiáng)現(xiàn)實(shí)(AR)的框架;開發(fā)者能夠使用它來(lái)快速的完成基本的AR功能開發(fā)。

軟硬件支持范圍

  • 硬件:A9處理器及以上(iPhone 6s)
  • 軟件:Xcode 9.0、iOS 11 及以上

必須同時(shí)具備上述條件。

需要其他什么

  • 相應(yīng)的3D模型(dae格式)
  • SceneKit、SpriteKit或Metal相關(guān)基礎(chǔ)知識(shí)(用做渲染)

ARKit的類結(jié)構(gòu)圖

查看大圖

ARKit類結(jié)構(gòu)圖

ARKit如何工作

假設(shè),我們需要實(shí)現(xiàn)的AR功能是:通過(guò)app在現(xiàn)實(shí)世界的桌子上放置一個(gè)杯子。我們需要通過(guò)怎么的步驟來(lái)實(shí)現(xiàn)這個(gè)功能呢?或者說(shuō)ARKit是怎么實(shí)現(xiàn)這樣的功能的呢?

AR放置的杯子

總結(jié)來(lái)說(shuō)有三個(gè)重要的部分:

  • 1、Tracking(實(shí)時(shí)捕捉周圍的信息,并處理生成相應(yīng)格式的數(shù)據(jù))
  • 2、Scene Understanding(理解當(dāng)前的場(chǎng)景,并找到合適的放置虛擬模型的位置)
  • 3、Rendering(渲染并展示)
Tracking

Tracking是ARKit的核心功能,它負(fù)責(zé)實(shí)時(shí)追蹤設(shè)備。

特性:

  • World tracking(通過(guò)World tracking能夠得到設(shè)備在現(xiàn)實(shí)世界的相對(duì)位置。)
  • Visual inertial odometry(同時(shí)使用攝像機(jī)捕捉的圖像和設(shè)備運(yùn)動(dòng)狀態(tài)來(lái)得到一個(gè)精確的設(shè)備位置和方向)
  • No external setup(無(wú)需外部的設(shè)置)

ARCamera中有兩個(gè)屬性trackingStatetrackingStateReason,開發(fā)者可以根據(jù)這兩個(gè)屬性的值,對(duì)用戶進(jìn)行相應(yīng)的提示。

Scene Understanding

Scene Understanding就是理解設(shè)備周圍環(huán)境的特征;例如平面檢測(cè),平面檢測(cè)就是檢測(cè)并分析出設(shè)備周圍環(huán)境中的平面。

特性:

  • Plane detection(平面檢測(cè))
  • Hit-testing(用于尋找現(xiàn)實(shí)世界的點(diǎn))
  • Light estimation(根據(jù)現(xiàn)實(shí)世界的環(huán)境來(lái)改變虛擬模型光照)
Rendering

渲染。

特性:

  • Easy integration(集成簡(jiǎn)單)
  • AR views(實(shí)現(xiàn)了大部分的渲染工作)
  • Custom rendering(可以自定義渲染)

ARKit的使用

ARKit是基于會(huì)話(ARSession)的一套API,ARSession處理包含Tracking、Scene Understanding以及渲染時(shí)需要的數(shù)據(jù)在內(nèi)的許多復(fù)雜的進(jìn)程。

ARSession和ARConfiguration

ARSession內(nèi)部使用了AVCaptureSession和CMMotionManager來(lái)獲取圖像信息和設(shè)備運(yùn)動(dòng)信息;根據(jù)ARConfiguration指定的Tracking類型來(lái)合成數(shù)據(jù),最終輸出ARFrame。每個(gè)ARFame包含了渲染需要的所有信息,可以把它理解成對(duì)應(yīng)時(shí)間的快照。想要獲得ARFrame有兩種方式:

  • 1、通過(guò)ARSession的委托,在每一幀更新時(shí)處理:- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame;
  • 2、通過(guò)currentFrame屬性,在需要時(shí)主動(dòng)獲取當(dāng)前幀:@property (nonatomic, copy, nullable, readonly) ARFrame *currentFrame;

ARConfiguration決定了Tracking類型;基類ARConfiguration有三個(gè)維度的追蹤,也即是設(shè)備的方向;子類ARWorldTrackingConfiguration擁有6個(gè)維度的追蹤,它即包含了設(shè)備的方向,也包含了設(shè)備在現(xiàn)實(shí)世界中的相對(duì)位置。

可以使用ARConfiguration的類屬性isSupported來(lái)判斷,當(dāng)前設(shè)備是否支持該模式的追蹤。@property(class, nonatomic, readonly) BOOL isSupported;

基本使用流程

想要使用ARKit,首要的步驟就是創(chuàng)建ARSession;其次,選用相應(yīng)的ARConfiguration來(lái)決定Tracking的類型;然后使會(huì)話運(yùn)行;之后的操作就是放置虛擬模型并渲染顯示。總結(jié)如下:

  • 1、創(chuàng)建ARSession對(duì)象
  • 2、創(chuàng)建相應(yīng)的ARConfiguration對(duì)象
  • 3、Run Session
  • 4、對(duì)場(chǎng)景做相應(yīng)的檢測(cè),找到防止虛擬模型的合適位置
  • 5、添加模型
  • 6、渲染顯示

上文中說(shuō)到SceneKitSpriteKit,在ARKit中,有兩個(gè)類:ARSCNViewARSKView是分別繼承自上述框架中的SCNView、SKView;ARKit結(jié)合這兩個(gè)框架為開發(fā)者提供了更加簡(jiǎn)單的使用過(guò)程,可以將ARSCNView(3D)、ARSKView(2D)理解成兩種渲染引擎(一個(gè)負(fù)責(zé)3D、一個(gè)負(fù)責(zé)2D),只要開發(fā)者選用其中的一種,那么將追蹤得到的幀數(shù)據(jù)就會(huì)自動(dòng)渲染并顯示到相應(yīng)的View上;對(duì)于特殊需求,也可以使用Metal來(lái)完成自定義的渲染。本文中都是使用ARSCNView來(lái)顯示場(chǎng)景的。

ARkit以及SceneKit的類關(guān)系圖(圖片摘取于:u013263917博客)

ARkit以及SCeneKit的類關(guān)系圖

使用ARSCNView時(shí)啟動(dòng)Tracking的代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 設(shè)置view
    self.sceneView.delegate = self;
    self.sceneView.automaticallyUpdatesLighting = NO;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    if (ARWorldTrackingConfiguration.isSupported) {
        // 防止熄屏
        [UIApplication sharedApplication].idleTimerDisabled = YES;
        
        // 創(chuàng)建一個(gè)能夠檢測(cè)水平面的configuration
        ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
        configuration.planeDetection = ARPlaneDetectionHorizontal;
    
        // 運(yùn)行
        [self.sceneView.session runWithConfiguration:configuration options:ARSessionRunOptionResetTracking|ARSessionRunOptionRemoveExistingAnchors];
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    // 暫停session
    [self.sceneView.session pause];
}

在完成上述的代碼之后,就能夠在ARSCNView上看到攝像機(jī)捕捉的景象。接下來(lái)就是找到合適的位置來(lái)放置虛擬的模型,如找一個(gè)平面,或者一個(gè)點(diǎn)。

對(duì)于平面,可以使用ARWorldTrackingConfiguration的屬性planeDetection來(lái)設(shè)置(目前只支持水平面),在檢測(cè)到平面之后,ARKit會(huì)自動(dòng)向Session中添加一個(gè)ARAnchor;ARAnchor代表現(xiàn)實(shí)世界中的一個(gè)位置,每一個(gè)添加到Session中的ARAnchor都會(huì)有一個(gè)與之對(duì)應(yīng)的節(jié)點(diǎn)(SCNNode),于是我們就可以在這個(gè)節(jié)點(diǎn)上添加模型(子節(jié)點(diǎn))。

如果想要將模型添加到指定的空間點(diǎn),ARKit為ARFrame提供了Hit-testing。方法聲明為:

- (NSArray<ARHitTestResult *> *)hitTest:(CGPoint)point types:(ARHitTestResultType)types;

Hit-testing就是從手機(jī)模擬發(fā)射一條射線去,尋找與現(xiàn)實(shí)世界的交點(diǎn)。

Hit-testing

其中point參數(shù),為當(dāng)前追蹤的圖片的相對(duì)位置,左上角是(0,0)右下角是(1,1);這個(gè)參數(shù)可以使用手勢(shì)來(lái)輸入。ARHitTestResultType是一個(gè)枚舉,決定用什么樣的方式去Hit-testing

typedef NS_OPTIONS(NSUInteger, ARHitTestResultType) {
    /** 返回射線上與特征點(diǎn)最接近的點(diǎn) */
    ARHitTestResultTypeFeaturePoint              = (1 << 0),
    
    /** 從當(dāng)前幀中確定一個(gè)平面,然后返回與平面的交點(diǎn) */
    ARHitTestResultTypeEstimatedHorizontalPlane  = (1 << 1),
    
    /** 將當(dāng)前已經(jīng)檢測(cè)到的平面看作無(wú)限大的平面,然后返回與這些平面的交點(diǎn) */
    ARHitTestResultTypeExistingPlane             = (1 << 3),
    
    /** 僅僅返回當(dāng)前平面范圍內(nèi)的交點(diǎn) */
    ARHitTestResultTypeExistingPlaneUsingExtent  = (1 << 4),
} NS_SWIFT_NAME(ARHitTestResult.ResultType);

代碼中結(jié)合手勢(shì)使用Hit-testing

- (IBAction)tapAction:(UITapGestureRecognizer *)sender {
    
    // 獲取當(dāng)前幀
    ARFrame *frame = self.sceneView.session.currentFrame;
    if (frame) {
        // 根據(jù)手勢(shì)設(shè)置點(diǎn)的位置
        CGPoint location = [sender locationInView:self.sceneView];
        CGSize size = self.sceneView.bounds.size;
        CGFloat x,y;
        
        x = location.x/size.width;
        y = location.y/size.height;
        
        // hit-testing
        NSArray<ARHitTestResult *> * results = [frame hitTest:CGPointMake(x, y) types:ARHitTestResultTypeEstimatedHorizontalPlane];
        if (results.count > 0) {
            // 將得到的第一個(gè)點(diǎn)添加到session
            ARHitTestResult *res = [results firstObject];
            ARAnchor *anchor = [[ARAnchor alloc] initWithTransform:res.worldTransform];
            [self.sceneView.session addAnchor:anchor];
        }
    }
}

添加hit-testing的Anchor后,可以在對(duì)應(yīng)的委托方法中,添加相應(yīng)的虛擬物體的模型

- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
        // 加載模型
        SCNScene *candle = [SCNScene sceneNamed:@"candle.scn" inDirectory:@"Models.scnassets/candle" options:nil];
        SCNNode *candleNode = [[candle.rootNode childNodes] firstObject];
        
        // 添加到對(duì)應(yīng)的節(jié)點(diǎn)上
        [node addChildNode:candleNode];
}

效果圖如下:

蠟燭

至此已經(jīng)完成了一個(gè)基本的AR應(yīng)用,如果需要完成更加復(fù)雜的應(yīng)用,還需要掌握很多關(guān)于SceneKit的知識(shí)(如模型的動(dòng)畫、坐標(biāo)系的轉(zhuǎn)換等)以及加入更復(fù)雜的邏輯和算法。

如何向一個(gè)工程中引入ARKit

  • 1、創(chuàng)建一個(gè)自定義個(gè)ViewController,并為其加上一個(gè)ARSCNView,將這個(gè)view設(shè)置為ViewController的一個(gè)屬性
step1.png
  • 2、初始化session和configuration
step2.png
  • 3、加載虛擬模型及其他操作

模型的導(dǎo)入

  • 1、創(chuàng)建一個(gè)文件夾,用"xxx.scnassets"的方式命名;
import1.png
  • 2、將該文件夾拖入工程;
import2.png
  • 3、將.dae格式的模型拖入該文件夾(在工程中拖入),然后選中Edit菜單,將其轉(zhuǎn)換成scn文件;
import3.png

轉(zhuǎn)換后的結(jié)果:


import4.png
  • 4、加載文件,獲取需要的節(jié)點(diǎn)。
    // 加載場(chǎng)景
    SCNScene *scene = [SCNScene sceneNamed:@"chameleon.scn" inDirectory:@"Models.scnassets" options:nil];
    
    // 獲取子節(jié)點(diǎn)
    NSArray *childNodes = [scene.rootNode childNodes];

參考資料以及Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,606評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,826評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,807評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,001評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評(píng)論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,243評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,709評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,996評(píng)論 2 374