簡(jiǎn)單使用 ARKit

概覽

什么是 AR摄乒?它不同于 VR悠反,VR 是一種沉浸式體驗(yàn),你眼前的一切都是虛擬的馍佑,根本不需要理會(huì)現(xiàn)實(shí)世界(當(dāng)然斋否,如果體驗(yàn) VR 的地方很小,你可能還需要注意一下走位拭荤,免得發(fā)生意外)茵臭,VR 是 Virtual Reality,也就是虛擬現(xiàn)實(shí)舅世,而 AR 是 Augmented Reality旦委,增強(qiáng)現(xiàn)實(shí)。AR 是對(duì)現(xiàn)實(shí)世界的一種補(bǔ)充雏亚,一種增強(qiáng)缨硝,你的大部分精力還是放在現(xiàn)實(shí)世界中。AR 被用來豐富化現(xiàn)實(shí)世界的圖像罢低,例如在一張什么都沒有的桌子上顯示出一個(gè)城堡追葡,又或者在一面干干凈凈的墻面上繪制涂鴉或擺放一面電視,但不同于普通的 PS 照片,AR 可以是動(dòng)態(tài)的宜肉,通過 AR 引擎創(chuàng)造出來的虛擬物體會(huì)根據(jù)人物的移動(dòng)而自動(dòng)調(diào)整位置匀钧,也就是說你從桌子的這個(gè)角走到另一個(gè)角,城堡依然在桌子上谬返,位置不變之斯,角度不變,甚至光照也不變遣铝,就好似真的有一座城堡在桌子上佑刷。

AR 和 VR 都是創(chuàng)造虛擬圖像的技術(shù),但前者是基于現(xiàn)實(shí)世界的酿炸,沒有現(xiàn)實(shí)世界的圖像瘫絮,AR 創(chuàng)造出來的圖像是沒什么意義的,而 VR 是完全虛擬的填硕,它會(huì)在虛擬世界中虛擬出一面桌子麦萤,然后在虛擬的桌子上在創(chuàng)造一個(gè)虛擬的城堡。

對(duì)于 AR 這樣一個(gè)神奇的技術(shù)扁眯,Apple 在 WWDC 2017 上順勢(shì)推出了 AR 引擎和開發(fā)框架壮莹,這個(gè)框架就叫做 ARKit

ARKit

Apple 的 ARKit 可以將你創(chuàng)造的 2D 平面對(duì)象和 3D 立體對(duì)象,通過 iOS 設(shè)備的攝像頭映射到現(xiàn)實(shí)世界中姻檀,透過屏幕你就能在當(dāng)前周圍的環(huán)境里看到你創(chuàng)造的對(duì)象 命满。

你可以通過 Apple 的 Metal、SpriteKit 和 SceneKit 來創(chuàng)造你的精靈绣版,你也可以通過強(qiáng)大的第三方引擎例如 Unity胶台、Unreal Engine 為你的 AR app 創(chuàng)造模型。

ARKit 基于 Visual Inertial Odometry (VIO) 技術(shù)實(shí)現(xiàn)杂抽,利用 iPhone 和 iPad 的各種傳感器提供的數(shù)據(jù)來計(jì)算你的當(dāng)前位置概作,同時(shí)更新虛擬物體的相對(duì)位置,還可以尋找到相對(duì)水平的平面默怨,例如桌子讯榕。所以這需要龐大的計(jì)算力,Apple 為此也做了一定限制:

  • 如果要使用 worldTeacking匙睹,你的設(shè)備所使用的處理器必須大于 A9 處理器

下面就讓我們一起來體驗(yàn)一下這神奇的框架吧愚屁!

使用 ARKit

在一切開始前,你需要打開最新的 Xcode 9.0 beta 版痕檬,然后新建一個(gè)工程:

1.新建一個(gè) Augmented Reality App

2.填寫 App 的 Bundle 名霎槐,在 Content Technology 一欄選擇 SceneKit,這表示我們將使用 SceneKit 來創(chuàng)造 AR 環(huán)境

3.選擇保存位置梦谜,一個(gè) AR 工程就新建完畢了

新建好以后丘跌,你會(huì)看到工程里已經(jīng)有一些文件袭景,而且和以往一樣,你可以直接運(yùn)行這個(gè)工程到你的設(shè)備上闭树,按下 Command + R 運(yùn)行在 iPhone 上試試吧耸棒!

在調(diào)試 AR app 的時(shí)候,你可能需要到處走動(dòng)报辱,牽著一根線可能會(huì)大大阻礙你的行動(dòng)与殃,幸運(yùn)的是 Xcode 9.0 開始支持了無線開發(fā),你可以以無線的方式將 App 安裝在設(shè)備上碍现,并且還能正常接收調(diào)試數(shù)據(jù)幅疼,具體怎么做請(qǐng)看我的探索 Xcode 9

Demo 工程是讓一艘飛船懸停在空中,如果你已經(jīng)運(yùn)行過這個(gè) Demo 了應(yīng)該會(huì)覺得效果還蠻不錯(cuò)昼接,雖然某些 AR 技術(shù)的通病 Apple 還沒有解決爽篷,讓我們先來看一看這個(gè)工程里相對(duì)重要的文件有哪些吧:

  • art.scnassets:這里面存放的就是場(chǎng)景文件,一個(gè)場(chǎng)景里可以有多個(gè)物體

  • ship.scn:我們的飛船就來自這個(gè)場(chǎng)景文件慢睡,你可以打開并編輯它

  • texture.png:這是一個(gè)紋理球文件逐工,每一個(gè) 3D 模型都應(yīng)該需要紋理,否則看上去會(huì)很單調(diào)一睁,除非你刻意創(chuàng)造那種場(chǎng)景钻弄。而這個(gè)紋理就是這艘飛船的紋理佃却。

  • ViewController.swift:默認(rèn)的視圖控制器者吁,它繼承于 UIViewController 并遵守 ARSCNViewDelegate 協(xié)議。

  • Main.storyboard:Storyboard 文件饲帅,里面有一些默認(rèn)的組件已經(jīng)被添加好了

剩下的一些資源文件和普通的 Cocoa touch 工程沒什么區(qū)別复凳,相信大家應(yīng)該都了解了。

那么讓我們繼續(xù)來看大家最關(guān)心的部分灶泵,ViewController 這個(gè)文件展示了顯示一個(gè)虛擬物體在現(xiàn)實(shí)世界中的最基本的步驟和內(nèi)容育八,相當(dāng)有指導(dǎo)意義,我們以方法和屬性區(qū)分赦邻,分別解釋髓棋。

默認(rèn)的 ViewController

@IBOutlet var sceneView: ARSCNView!

這就是 Xcode 幫我們創(chuàng)建好的一個(gè) ARSceneView 對(duì)象,而且做好了牽線工作惶洲。這個(gè) Scene 和普通的 SceneKit 的 Scene 不同的是按声,它是 AR Scene,專門顯示 AR 的

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate 設(shè)置 view 的代理
        sceneView.delegate = self

        // Show statistics such as fps and timing information 顯示調(diào)試信息
        sceneView.showsStatistics = true

        // Create a new scene 創(chuàng)造一個(gè)新的場(chǎng)景
        let scene = SCNScene(named: "art.scnassets/ship.scn")!

        // Set the scene to the view 使默認(rèn)場(chǎng)景為我們新創(chuàng)建的場(chǎng)景
        sceneView.scene = scene
    }

在 viewDidLoad 中恬吕,我們可以為創(chuàng)建好的 sceneView 設(shè)置代理签则,showStatistics 屬性可以指定是否顯示調(diào)試信息,這些信息包含 fps 值铐料、時(shí)間信息等渐裂。

我們之前在資源文件里看到了豺旬,有一個(gè)飛船的場(chǎng)景文件,這個(gè)場(chǎng)景文件也是在這里被載入的柒凉,使用 SCNScene 的初始化方法 init(named:) 來載入一個(gè)場(chǎng)景文件族阅,最后我們將 sceneView 的默認(rèn)場(chǎng)景替換成我們載入的場(chǎng)景。

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Create a session configuration
        let configuration = ARWorldTrackingSessionConfiguration()

        // Run the view's session
        sceneView.session.run(configuration)
    }

每一個(gè) AR 場(chǎng)景被創(chuàng)建時(shí)扛拨,它都需要一個(gè)配置類來告訴它應(yīng)該使用怎樣的方式去運(yùn)行耘分,配置類一共有兩種:

  • ARWorldTrackingSessionConfiguration

  • ARSessionConfiguration

這里使用的就是第一種,兩者的區(qū)別在于物體的擺放方式:

  • 設(shè)置為 ARWorldTrackingSessionConfiguration 時(shí)绑警,物體放在基于現(xiàn)實(shí)世界的坐標(biāo)系求泰,你的攝像頭只是這個(gè)坐標(biāo)系的另一個(gè)點(diǎn),移動(dòng)設(shè)備的時(shí)候物體是相對(duì)坐標(biāo)系靜止的计盒。
ARWorldTrackingSessionConfiguration
  • 設(shè)置為 ARSessionConfiguration 時(shí)渴频,坐標(biāo)系以你的設(shè)備為基準(zhǔn),你的設(shè)備平移時(shí)北启,整個(gè)坐標(biāo)系也跟著平移卜朗,坐標(biāo)系上的物體也跟著平移,所以攝像頭和物體是相對(duì)靜止的咕村,只有設(shè)備橫向旋轉(zhuǎn)時(shí)能觀察坐標(biāo)系的其他部分的元素场钉。
ARSessionConfiguration

在創(chuàng)建好配置類的對(duì)象后,你就可以使用 sceneView 的 session 來啟動(dòng)一次 AR session懈涛,這里的 session 就是每一個(gè) AR 進(jìn)程所需要的 session 對(duì)話逛万,你可以使用 run() 方法來啟動(dòng)一個(gè) session。

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }

當(dāng)你不希望 session 繼續(xù)占用系統(tǒng)資源時(shí)批钠,你可以使用 pause() 來停止一次 session宇植,你可以再一次使用 run 來啟動(dòng)新的 session。

另外埋心,你還可以在 session 執(zhí)行的過程中動(dòng)態(tài)更新配置類指郁。

    // Override to create and configure nodes for anchors added to the view's session.

    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()
        return node
    }

    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

    }

    func session(_ session: ARSession, didFailWithError error: Error) {
        // Present an error message to the user
    }

    func sessionWasInterrupted(_ session: ARSession) {
        // Inform the user that the session has been interrupted, for example, by presenting an overlay
    }

    func sessionInterruptionEnded(_ session: ARSession) {
        // Reset tracking and/or remove existing anchors if consistent tracking is required
    }

這里就列出了一些 ARSCNViewDelegate 中的代理方法,其中:

  • renderer(:nodeFor:):新建一個(gè) Anchor(錨點(diǎn))時(shí)會(huì)調(diào)用

  • renderer(:updateAtTime:):更新場(chǎng)景時(shí)會(huì)調(diào)用

  • session(:didFailWithError:):出現(xiàn)錯(cuò)誤時(shí)會(huì)調(diào)用拷呆,此時(shí)會(huì)終止 session

  • sessionWasInterrupted(:):中斷 session 時(shí)會(huì)調(diào)用

  • sessionInterruptionEnded(:):中斷結(jié)束時(shí)會(huì)調(diào)用

到這里大家都應(yīng)該知道一個(gè)場(chǎng)景的基本構(gòu)造闲坎,以及如何載入一個(gè)場(chǎng)景。

添加一張“照片”到 AR 場(chǎng)景中

大家應(yīng)該都發(fā)現(xiàn)了茬斧,我們是利用 SceneKit 創(chuàng)建的 AR 場(chǎng)景腰懂,所以我們可以將一部分 SceneKit 的東西拿來用,使用 SceneKit 創(chuàng)造的三維模型將其載入到 AR 世界里去啥供,事實(shí)上悯恍,我們的 scn 場(chǎng)景文件本身也就是 SceneKit 的概念。
在這里我們將利用 SCNPlane 類來創(chuàng)造一個(gè)平面伙狐,然后設(shè)置這個(gè)平面的紋理為一張照片涮毫,在我們點(diǎn)擊屏幕時(shí)將這個(gè)對(duì)象添加到 AR 場(chǎng)景中瞬欧。

1.在 touchesBegan 中實(shí)現(xiàn)
既然是點(diǎn)擊屏幕添加物體,那么就可以在 touchesBegan 中完成

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // code here
}

2.獲取當(dāng)前幀
對(duì)于 AR 場(chǎng)景罢防,當(dāng)前幀不僅僅包含了幀信息和圖像信息艘虎,還包含了當(dāng)前 ARCamera 的坐標(biāo)信息、sceneView 的大小等等咒吐,我們要實(shí)現(xiàn)在屏幕前添加一個(gè)物體野建,那么就得獲取當(dāng)前 Camera 的位置,否則我們添加的物體可能在任何一個(gè)地方恬叹,甚至你找不到的地方

// 從 session 中獲取 currentFrame
guard let currentFrame = sceneView.session.currentFrame else { return }

3.創(chuàng)建一個(gè) Node
要?jiǎng)?chuàng)建一個(gè) Node候生,你需要一個(gè)繼承自 SCNGeometry 的對(duì)象,這里我們使用的 SCNPlane 就繼承自 SCNGeometry

// 創(chuàng)建一個(gè) plane绽昼。并設(shè)置大小唯鸭,這里的大小單位接近米,不能太大硅确,否則最后會(huì)擋住我們的視線目溉,看不出效果
let plane = SCNPlane(width: 0.6, height: 0.4)

// Meterial 就是我們的材料,也就是紋理菱农,我們?cè)O(shè)置紋理的內(nèi)容為一個(gè) UIImage 對(duì)象
plane.firstMaterial?.diffuse.contents = UIImage(named: "material.jpg")
plane.firstMaterial?.lightingModel = .constant

// 利用創(chuàng)建好的 plane 來創(chuàng)建一個(gè)精靈(Node)
let planeNode = SCNNode(geometry: plane)

// 最后把精靈加入到 sceneView 的根節(jié)點(diǎn)
sceneView.scene.rootNode.addChildNode(planeNode)

每一個(gè) scene 都有一個(gè)根節(jié)點(diǎn)缭付,它類似于一個(gè) scene 的坐標(biāo)中心,所有子節(jié)點(diǎn)都依附于根節(jié)點(diǎn)循未,根節(jié)點(diǎn)產(chǎn)生的位移陷猫、旋轉(zhuǎn)變化都會(huì)應(yīng)用于子節(jié)點(diǎn)。

4.設(shè)置新節(jié)點(diǎn)的位置
我們說只厘,需要把新加入的物體放在我們面前烙丛,那就必須要指定好它的詳細(xì)位置舅巷,這時(shí)候我們最開始獲取的 currentFrame 就有用了

// 熟悉 SceneKit 的朋友應(yīng)該都了解這里的操作羔味,這里的重點(diǎn)是利用 currentFrame 的 camera 屬性來獲取 transform
// 這個(gè) transform 的各種位置屬性就是當(dāng)前攝像機(jī)所處的位置信息,所以我們可以直接利用它
var translation = matrix_identity_float4x4
translation.columns.3.z = -20
let transform = matrix_multiply(currentFrame.camera.transform, translation)

// 最后把 transform 傳給 node 的 simdTransform
planeNode.simdTransform = transform

5.運(yùn)行钠右,測(cè)試
現(xiàn)在重新編譯工程赋元,并運(yùn)行在設(shè)備上,每當(dāng)我們點(diǎn)擊一下屏幕時(shí)飒房,面前都會(huì)有一張我們的照片出現(xiàn)搁凸,而且此時(shí)你可以移動(dòng)相機(jī),在其他地方繼續(xù)添加照片狠毯,最后可以創(chuàng)造出一個(gè)很帥氣的場(chǎng)景~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末护糖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嚼松,更是在濱河造成了極大的恐慌嫡良,老刑警劉巖锰扶,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寝受,居然都是意外死亡坷牛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門很澄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來京闰,“玉大人,你說我怎么就攤上這事甩苛□彘梗” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵讯蒲,是天一觀的道長(zhǎng)捐迫。 經(jīng)常有香客問我,道長(zhǎng)爱葵,這世上最難降的妖魔是什么施戴? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮萌丈,結(jié)果婚禮上赞哗,老公的妹妹穿的比我還像新娘。我一直安慰自己辆雾,他們只是感情好肪笋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著度迂,像睡著了一般藤乙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惭墓,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天坛梁,我揣著相機(jī)與錄音,去河邊找鬼腊凶。 笑死划咐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钧萍。 我是一名探鬼主播褐缠,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼风瘦!你這毒婦竟也來了队魏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤万搔,失蹤者是張志新(化名)和其女友劉穎胡桨,沒想到半個(gè)月后俐载,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡登失,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年遏佣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揽浙。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡状婶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馅巷,到底是詐尸還是另有隱情膛虫,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布钓猬,位于F島的核電站稍刀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敞曹。R本人自食惡果不足惜账月,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澳迫。 院中可真熱鬧局齿,春花似錦、人聲如沸橄登。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拢锹。三九已至谣妻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卒稳,已是汗流浹背蹋半。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留展哭,地道東北人湃窍。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓闻蛀,卻偏偏與公主長(zhǎng)得像匪傍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子觉痛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • ARKit ARKit框架通過集成iOS設(shè)備攝像頭和運(yùn)動(dòng)功能役衡,在您的應(yīng)用程序或游戲中產(chǎn)生增強(qiáng)現(xiàn)實(shí)體驗(yàn)。 概述 增強(qiáng)...
    暗夜夜夜行路閱讀 5,788評(píng)論 0 17
  • 一薪棒、AR簡(jiǎn)介: 增強(qiáng)現(xiàn)實(shí)技術(shù)(Augmented Reality手蝎,簡(jiǎn)稱 AR)榕莺,是一種實(shí)時(shí)地計(jì)算攝影機(jī)影像的位置及...
    rectinajh閱讀 2,069評(píng)論 0 6
  • 一、AR簡(jiǎn)介: 多媒體捕捉現(xiàn)實(shí)圖像:如攝像頭 三維建模:3D立體模型 傳感器追蹤:主要追蹤現(xiàn)實(shí)世界動(dòng)態(tài)物體的六軸變...
    DeerRun閱讀 1,418評(píng)論 0 2
  • 大名鼎鼎的松下公司創(chuàng)始人松下幸之助曾提出:“松下只招70分水平的人棵介,不招90分優(yōu)秀的人才”钉鸯。他的主要理由在于,越優(yōu)...
    彭榮模HR視野閱讀 565評(píng)論 0 0
  • 敬畏之心——夫子家 我出生在河邊邮辽,從小就聽老人們常說一句話:在河里淹死的活喊,大多是會(huì)水的人解虱。 所以,我從小就有些怕水...
    夫子家閱讀 246評(píng)論 1 2