ARKit 從零到一 第3部分:放置幾何體并應(yīng)用物理學(xué)

上一篇文章里我們用 ARKit 來檢測(cè)真實(shí)生活中的平面低斋,然后給這些平面添加了視覺效果俐筋。在這篇文章中静秆,我會(huì)開始向 AR 體驗(yàn)添加虛擬內(nèi)容,并與檢測(cè)到的平面進(jìn)行交互巡李。

在這篇文章的最后抚笔,我們能夠把小方塊丟到世界里,并在小方塊上應(yīng)用逼真的物理學(xué)侨拦,以便它們彼此相互作用殊橙,同時(shí)還會(huì)制造迷你沖擊波來讓小方塊飛出去。

下面是實(shí)際的演示視頻狱从,可以看到首先獲取了水平面膨蛮,然后添加了一些 3D 小方塊并與場(chǎng)景交互,最后制造了一些迷你沖擊波來讓小方塊飛出去:

視頻

和以前一樣矫夯,你可以參照這里的代碼:https://github.com/josephchang10/ARCube/tree/part3

命中測(cè)試

在第一篇教程中鸽疾,我們可以在任意 X,Y,Z 位置插入虛擬 3D 內(nèi)容,并在真實(shí)世界里渲染和追蹤⊙得玻現(xiàn)在我們掌握了平面檢測(cè)制肮,我想添加一些內(nèi)容并與這些平面交互。完成后從 app 中看過去递沪,你的桌子豺鼻、椅子、地板等等上面就像都擺了東西款慨。

在此 app 中儒飒,如果用戶點(diǎn)擊屏幕,就會(huì)執(zhí)行一次命中測(cè)試(hit test)檩奠,即獲取屏幕的 2D 坐標(biāo)桩了,并從攝像頭原點(diǎn)處通過屏幕的 2D 坐標(biāo)(在投影平面上有 3D 位置)發(fā)射一道射線到場(chǎng)景中。如果射線與某個(gè)平面相交埠戳,就會(huì)獲得命中結(jié)果井誉,然后利用射線和平面相交的 3D 坐標(biāo),在此 3D 位置放置內(nèi)容整胃。

這段代碼相當(dāng)簡(jiǎn)單颗圣,ARSCNView 包含一個(gè) hitTest 方法,只要傳入屏幕坐標(biāo)屁使,它會(huì)負(fù)責(zé)從攝像頭原點(diǎn)投影射線在岂,并穿過 3D 環(huán)境中對(duì)應(yīng)屏幕坐標(biāo)的點(diǎn),最后返回結(jié)果:

@objc func handleTapFrom(recognizer: UITapGestureRecognizer) {
        // 獲取屏幕空間坐標(biāo)并傳遞給 ARSCNView 實(shí)例的 hitTest 方法
        let tapPoint = recognizer.location(in: sceneView)
        let result = sceneView.hitTest(tapPoint, types: .existingPlaneUsingExtent)
        
        // 如果射線與某個(gè)平面幾何體相交蛮寂,就會(huì)返回該平面蔽午,以離攝像頭的距離升序排序
        // 如果命中多次,用距離最近的平面
        if let hitResult = result.first {
            insertGeometry(hitResult)
        }
    }

有了 ARHitTestResult 就可以得到射線/平面相交點(diǎn)的世界坐標(biāo)共郭,并在該位置放置虛擬內(nèi)容祠丝。這篇文章里只會(huì)插入簡(jiǎn)單的小方塊疾呻,后面的文章里則會(huì)讓物體看起來更真實(shí):

func insertGeometry(_ hitResult: ARHitTestResult) {
  
        let dimension: CGFloat = 0.1
        let cube = SCNBox(width: dimension, height: dimension, length: dimension, chamferRadius: 0)
        let node = SCNNode(geometry: cube)
        
        // physicsBody 會(huì)讓 SceneKit 用物理引擎控制該幾何體
        node.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
        
        node.physicsBody?.mass = 2
        node.physicsBody?.categoryBitMask = CollisionCategory.cube.rawValue
        
        // 把幾何體插在用戶點(diǎn)擊的點(diǎn)再稍高一點(diǎn)的位置,以便使用物理引擎來掉落到平面上
        let insertionYOffset: Float = 0.5
        node.position = SCNVector3Make(hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y + insertionYOffset, hitResult.worldTransform.columns.3.z)
        sceneView.scene.rootNode.addChildNode(node)

          // 將小方塊添加到場(chǎng)景中
        boxes.append(node)
    }

添加物理學(xué)

AR 理應(yīng)增強(qiáng)現(xiàn)實(shí)世界写半,所以為了讓物體的感覺更加真實(shí)岸蜗,需要添加一些物理學(xué)原理來給予重力感。

上面的代碼里每個(gè)小方塊都給定了 physicsBody叠蝇,以便讓 SceneKit 用物理引擎來控制該幾何體璃岳。每個(gè) ARKit 檢測(cè)的平面我也給定了 physicsBody,以便讓小方塊與平面交互(查看 github repo 中的 Plane.swift 類可以獲得更多細(xì)節(jié))悔捶。

停止平面檢測(cè)

有了一定數(shù)量的平面后铃慷,就不希望 ARKit 再繼續(xù)提供新平面了,因?yàn)檫@可能會(huì)更新目前已存在的平面蜕该,并影響已經(jīng)添加到世界中的幾何體犁柜。

在這個(gè) app 里,如果用戶用兩只手指長(zhǎng)按一秒堂淡,就會(huì)隱藏所有的平面并關(guān)閉平面檢測(cè)馋缅。只需更新 ARSession configuration 的 planeDetection 屬性并再次 run 一遍 session 即可。默認(rèn)情況下绢淀,session 會(huì)保留相同的坐標(biāo)系以及所有 anchor:

// 獲取當(dāng)前的 session configuration
if let configuration = sceneView.session.configuration as? ARWorldTrackingSessionConfiguration{
              //關(guān)閉平面檢測(cè)和更新
            configuration.planeDetection = .init(rawValue: 0) // ARPlaneDetectionNone
              // 再次 run session 以應(yīng)用改變
            sceneView.session.run(configuration)
        }

示例代碼

所有的示例代碼都在這里:https://github.com/josephchang10/ARCube/tree/part3

接下來

下篇文章里會(huì)強(qiáng)化之前我們寫過的代碼萤悴,并添加一些 UI 控件來開啟/關(guān)閉某些功能。還會(huì)使用光線和紋理皆的,以便讓插入的幾何體看起來更加真實(shí)覆履。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市费薄,隨后出現(xiàn)的幾起案子硝全,更是在濱河造成了極大的恐慌,老刑警劉巖楞抡,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柳沙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拌倍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門噪径,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柱恤,“玉大人,你說我怎么就攤上這事找爱」K常” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵车摄,是天一觀的道長(zhǎng)寺谤。 經(jīng)常有香客問我仑鸥,道長(zhǎng),這世上最難降的妖魔是什么变屁? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任眼俊,我火速辦了婚禮,結(jié)果婚禮上粟关,老公的妹妹穿的比我還像新娘疮胖。我一直安慰自己,他們只是感情好闷板,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布澎灸。 她就那樣靜靜地躺著,像睡著了一般遮晚。 火紅的嫁衣襯著肌膚如雪性昭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天县遣,我揣著相機(jī)與錄音糜颠,去河邊找鬼。 笑死艺玲,一個(gè)胖子當(dāng)著我的面吹牛括蝠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饭聚,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼忌警,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了秒梳?” 一聲冷哼從身側(cè)響起法绵,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酪碘,沒想到半個(gè)月后朋譬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兴垦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年徙赢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片探越。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狡赐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钦幔,到底是詐尸還是另有隱情枕屉,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布鲤氢,位于F島的核電站搀擂,受9級(jí)特大地震影響西潘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哨颂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一喷市、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咆蒿,春花似錦东抹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒂破,卻和暖如春馏谨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背附迷。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工惧互, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喇伯。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓喊儡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親稻据。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艾猜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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