ARKit從入門到精通(1)--顯示Cube(原生方法實現)

在全新AR開發專欄的第一篇咱們經過一個簡單的project(在顯示環境放置一個cube)來了解ARKit的核心功能與API特性。經過這個過程,你將瞭解ARKit如何在真實的設備中工做,從而與建立的3D對象進行交互。


前提說明

1.本部分教程使用的是原生iOS開發,目前不涉及Unity,主要使用SceneKit。
node

2.使用的軟件版本:Xcode 9。swift

3.使用的開發語言版本:Swift 4bash

4.本系列專欄但願經過簡潔的語言與圖片幫助你們更好的理解ARKit開發流程,幫助你們開發出炫酷的AR應用。微信

Step 1: 建立項目

打開Xcode,點擊File > New > Project…,選擇Single View App,點擊Next建立項目,命名爲ARKitDemo。以下圖操做所示:session


設置SceneKit Viewapp

打開Main.storyboard,將ARKit SceneKit視圖拖放到視圖控制器上。
ide


而後將ARKit SceneKit視圖約束填充整個視圖控制器。測試


Step 2: 編輯代碼實現open camera

鏈接IBOutletui

ViewController.swift文件的頂部添加一個import語句來導入ARKit:spa

import ARKit複製代碼

而後按住control鍵並從ARKit SceneKit視圖拖拽到ViewController.swift文件。當提示時,命名IBOutlet sceneView。能夠刪除didReceiveMemoryWarning() 方法,目前咱們並不須要它。


配置ARSCNView Session

咱們的AR應用程序是經過攝像頭觀察世界和周圍的環境。因此接下來咱們須要設置Camera:

配置ARKit SceneKit View。在ViewController類中插入如下代碼:

override func viewWillAppear(_ animated: Bool) {    
super.viewWillAppear(animated)    
let configuration = ARWorldTrackingConfiguration()    
sceneView.session.run(configuration)
}複製代碼

viewWillAppear(_:)方法中,咱們初始化了一個名爲ARWorldTrackingConfiguration的AR配置。主要用於實現World Tracking功能。

The World Tracking配置跟蹤設備的方向和位置,它還能經過設備的Camera探測真實世界的表面。

設置sceneView’s AR session來運行咱們剛剛初始化的配置。AR session管理視圖內容的運動跟蹤和camera圖像處理。

如今在ViewController中添加另外一個方法:

override func viewWillDisappear(_ animated: Bool) {    
super.viewWillDisappear(animated)    
sceneView.session.pause()
}複製代碼

在viewWillDisappear(_:)方法中主要處理:中止tracking和視圖內容的圖像。

Camera 受權

在咱們運行應用程序以前,咱們須要通知用戶咱們將使用他們設備的攝像頭實現加強現實功能。這是iOS 10發佈以來的一個要求。

打開Info.plist。右鍵單擊空白區域並選擇Add row。設置私隱相機使用說明鍵。值能夠設置爲Augmented Reality。以下圖所示:


接下來咱們提早測試下Camera是否能夠順利的調用出來。將測試手機鏈接到Mac上。在Xcode上構建並運行該項目。該應用程序應該會提示你容許攝像頭進入。以下圖所示:


Step 3: 添加3D物體

插入如下代碼到你的ViewController類:

func addBox() {
    let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(0, 0, -0.2)
    
    let scene = SCNScene()
    scene.rootNode.addChildNode(boxNode)
    sceneView.scene = scene
}複製代碼

  • 建立一個Box,1 Float = 1 meter。

  • 建立一個node。node表示物體在三維空間中的位置和座標。node自己沒有可見的內容。

  • 給node設置一個形狀(Box)。

  • 設置box的位置。這個位置相對於camera的,右邊是X正,左邊是X負。上面表示Y正,向下表示Y負。向後表示Z正,向前表示Z負。

  • 建立一個scene(SceneKit scene),將box添加到場景中去。

  • sceneView的scene設置爲顯示剛剛建立的場景。

override func viewDidLoad() {
    super.viewDidLoad()
    addBox()
}複製代碼

接下來Build,打開camera,出現白色的box,效果以下圖:


addBox()的方法也能夠這樣寫:

func addBox() {
    let box = SCNBox(width: 0.05, height: 0.05, length: 0.05, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(0, 0, -0.2)
    
    sceneView.scene.rootNode.addChildNode(boxNode)
}複製代碼

Step 4: 添加手勢(點擊刪除3D物體)

在ViewController.swift文件中插入如下方法:

@objc func didTap(withGestureRecognizer recognizer: UIGestureRecognizer) {
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation)
    guard let node = hitTestResults.first?.node else { return }
    node.removeFromParentNode()
}複製代碼

建立了一個didTap(帶有gesturerecognizer:)方法。檢索用戶相對於sceneView的點擊位置,而後t查看是否點擊了任何node。而後從hitTestResults中找到第一個node。若是結果確實包含至少一個node,那麼咱們將從其父節點刪除第一個節點。

在測試刪除對象以前,更新viewDidLoad()方法,添加對addTapGestureToSceneView()方法的調用:

override func viewDidLoad() {
    super.viewDidLoad()
    
    addBox()
    addTapGestureToSceneView()
}複製代碼

Step 5: 添加多個3D物體

在ViewController類的末尾建立一個extension:

extension float4x4 {
    var translation: float3 {
        let translation = self.columns.3
        return float3(translation.x, translation.y, translation.z)
    }
}複製代碼

extension將矩陣轉換爲float3。修改addBox()方法:

func addBox(x: Float = 0, y: Float = 0, z: Float = -0.2) {
    let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(x, y, z)
    
    sceneView.scene.rootNode.addChildNode(boxNode)
}複製代碼

修改didTap(使用gesturerecognizer:)方法,在guard let語句內部和return語句以前。添加如下代碼:

let hitTestResultsWithFeaturePoints = sceneView.hitTest(tapLocation, types: .featurePoint)
 
if let hitTestResultWithFeaturePoints = hitTestResultsWithFeaturePoints.first {
    let translation = hitTestResultWithFeaturePoints.worldTransform.translation
    addBox(x: translation.x, y: translation.y, z: translation.z)
}複製代碼

接下來實現使用x、y和z在檢測到的點擊時添加一個新的box。didTap(withGestureRecognizer:)方法的代碼以下:

@objc func didTap(withGestureRecognizer recognizer: UIGestureRecognizer) {
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation)
    guard let node = hitTestResults.first?.node else {
        let hitTestResultsWithFeaturePoints = sceneView.hitTest(tapLocation, types: .featurePoint)
        if let hitTestResultWithFeaturePoints = hitTestResultsWithFeaturePoints.first {
            let translation = hitTestResultWithFeaturePoints.worldTransform.translation
            addBox(x: translation.x, y: translation.y, z: translation.z)
        }
        return
    }
    node.removeFromParentNode()
}複製代碼

運行效果以下圖:


參考連接:https://www.appcoda.com/arkit-introduction-scenekit/


------AR Portal(AR開發者社區)整理

關注微信公衆號(AR開發者交流社區,提供AR開發乾貨,推進AR內容發展):AR開發者社區

相關文章
相關標籤/搜索