一、ARKit初探索


(一) AR(增強現(xiàn)實技術(shù))介紹

增強現(xiàn)實(Augmented Reality,簡稱 AR),是一種實時地計算攝影機影像的位置及角度并加上相應(yīng)圖像的技術(shù),這種技術(shù)的目標是在屏幕上把虛擬世界套在現(xiàn)實世界并進行互動。

增強現(xiàn)實技術(shù),不僅展現(xiàn)了真實世界的信息,而且將虛擬的信息同時顯示出來,兩種信息相互補充、疊加。在視覺化的增強現(xiàn)實中,用戶利用頭盔顯示器,把真實世界與電腦圖形多重合成在一起,便可以看到真實的世界圍繞著它。


(二) ARKit概述

1. 2017.06.06 蘋果iOS11發(fā)布ARKit框架。

? ? ? 為了在真實空間和虛擬空間之間創(chuàng)建一個對應(yīng)關(guān)系,ARKit使用一種稱為視覺慣性測距的技術(shù)。該過程將來自iOS設(shè)備的運動感應(yīng)硬件的信息與設(shè)備相機可見的場景的計算機視覺分析相結(jié)合。ARKit識別場景圖像中的顯著特征,跟蹤視頻幀中這些特征位置的差異,并將該信息與運動感測數(shù)據(jù)進行比較。結(jié)果是設(shè)備的位置和運動的高精度模型。

? ? ? ARKit可以將2D或3D元素從設(shè)備的相機中添加到實時視圖中,使得這些元素似乎在現(xiàn)實世界中。ARKit結(jié)合了設(shè)備運動跟蹤,攝像機場景拍攝,高級場景處理和顯示便利,他可讓你輕松創(chuàng)建無與倫比的iPhone和iPad增強現(xiàn)實體驗。

2. 開發(fā)要求 Xcode9及以上、iOS11以及處理器要在A9及以上(6S機型及以上)

? ? ? 目前只有Beta版本,鏈接地址: https://developer.apple.com/download/


(三)初步探索

1.首先我們來了解一下ARSession類

? ? 管理設(shè)備相機的共享對象和增強現(xiàn)實體驗所需的運動處理。

? ? 一個ARSession對象協(xié)調(diào)ARKit代表你執(zhí)行的主要過程,以創(chuàng)建增強的現(xiàn)實體驗。這些過程包括從設(shè)備的運動感測硬件讀取數(shù)據(jù),控制設(shè)備的內(nèi)置相機,以及對拍攝的相機圖像執(zhí)行圖像分析。會話綜合了所有這些結(jié)果,以建立設(shè)備所在真實世界空間與你為AR內(nèi)容建模的虛擬空間之間的對應(yīng)關(guān)系。

? ? ARKit構(gòu)建的每個AR體驗都需要一個ARSession對象。如果您使用ARSCNView(顯示使用3D SceneKit內(nèi)容增強相機視圖的AR體驗的視圖)或ARSKView(用于顯示使用2D SpriteKit內(nèi)容增強相機視圖的AR體驗的視圖)對象來輕松構(gòu)建AR體驗的可視化部分,則視圖對象包含一個ARSession實例。如果您為AR內(nèi)容構(gòu)建自己的渲染器,則需要自己實例化和維護一個ARSession對象。

? ? 運行會話需要會話配置:AROrientationTrackingConfiguration? ARWorldTrackingSessionConfiguration 類的實例或其子類。這些類確定ARKit如何跟蹤設(shè)備相對于現(xiàn)實世界的位置和運動,從而影響您可以創(chuàng)建的AR體驗的種類。


2.接著我將一步步指導大家使用 使用ARSCNView來創(chuàng)建簡單的3D AR效果

(1)打開Xcode9 bete版本,我在這里使用的是beta5版本。我們新建一個工程,選擇Augmented Reality APP,點擊Next

(2)Content Technology中選擇SceneKit,Next

(3)ARSCNView

創(chuàng)建完成項目以后我們可以看到 art.scnassets->ship.scn 中蘋果自帶了一個飛機的模型


我們先直接在iOS11的設(shè)備上運行一下看看效果怎么樣~~~

出現(xiàn)了~~~出現(xiàn)了~一個3D的小飛機,我們可以靠近他上下左右打量他一下,^V^怎么樣感覺還不錯吧

接下來我們開始看下代碼(項目創(chuàng)建出來沒有模型的或者OoO想看我代碼的小伙伴們,猛戳~:https://github.com/az52013141711/ARKit_ARSCNView)

首先我們看下Main.storyboard中已經(jīng)為我們添加了一個ARSCNView

接著我們來到ViewController.swift

@IBOutlet var sceneView:ARSCNView!

override func viewDidLoad() {

? ? super.viewDidLoad()

? ? // Set the view's delegate

? ? //設(shè)置代理

? ? sceneView.delegate = self

? ? // Show statistics such as fps and timing information

? ? //顯示統(tǒng)計信息,如fps

? ? sceneView.showsStatistics = true

? ? // Create a new scene

? ? //用模型創(chuàng)建場景(scn格式文件是一個基于3D建模的文件,使用3DMax軟件可以創(chuàng)建,這里系統(tǒng)有一個默認的3D飛機)

? ? let scene = SCNScene(named:"art.scnassets/ship.scn")!

? ? // Set the scene to the view

? ? //將場景設(shè)置到ARSCNView上顯示

? ? sceneView.scene = scene

}

override func viewWillAppear(_animated:Bool) {

? ? super.viewWillAppear(animated)

? ? // Create a session configuration

? ? /*創(chuàng)建一個會話配置

? ? 這些ARSCNView和ARSKView類包括ARSession管理創(chuàng)建AR體驗所需的運動跟蹤和圖像處理的對象。? ? 但是,要運行會話,您必須提供會話配置。

? ? ARWorldTrackingConfiguration 跟蹤設(shè)備的方向和位置以及檢測設(shè)備相機所看到的實際表面的配置

? ? AROrientationTrackingConfiguration 僅跟蹤設(shè)備方向的配置

? ? ARConfiguration AR會話配置的抽象基類*/

? ? let configuration = ARWorldTrackingConfiguration()

? ? // Run the view's session

? ? //運行視圖的會話

? ? sceneView.session.run(configuration)

}

override func viewWillDisappear(_animated:Bool) {

? ? super.viewWillDisappear(animated)

? ? // Pause the view's session

? ? //暫停試圖的會話

? ? sceneView.session.pause()

}

就只有這短短的幾句代碼就可以實現(xiàn)了一個簡單的3D飛機~蘋果簡直太棒了~~

(4)SCNScene介紹。ARSCNView顯示需要一個場景(SCNScene)

SCNScene具有連接的幾何圖形,燈光,照相機和其他屬性的節(jié)點的層次結(jié)構(gòu),其一起形成可顯示的3D場景。

SCNScene包含在SceneKit中,SceneKit是iOS8之后蘋果推出了一個3D模型渲染框架

下圖中可以看到ARSCNView、SCNView與SCNScene的關(guān)系

SceneKit將內(nèi)容實現(xiàn)為節(jié)點的分層樹結(jié)構(gòu),也稱為場景圖。一個場景由一個根節(jié)點組成,該節(jié)點定義了場景世界的坐標空間,以及使用可見內(nèi)容填充世界的其他節(jié)點。SceneKit在視圖中顯示場景,處理場景圖和執(zhí)行動畫,然后高效地渲染GPU上的每個幀。

在使用SceneKit之前,我們熟悉基本的圖形概念,如坐標系和三維幾何的數(shù)學。SceneKit使用右手坐標系,其中(默認情況下)視圖的方向沿著負z軸,如下所示。


前面有說ARKit使用視覺慣性測距技術(shù)來實現(xiàn)的,這樣會在我們當前位置建立一個三維的擁有尺度的坐標系

①創(chuàng)建場景(SCNScene)方法

A、可以從使用外部3D創(chuàng)作工具創(chuàng)建的文件中獲取場景。如果您在應(yīng)用程序的資源管理資源目錄中包含場景文件,則Xcode會壓縮它們以獲得最佳的SceneKit加載性能。要加載場景文件,使用init(named:) 、init(named:inDirectory:options:)、 init(url:options:)方法或?qū)嵗?a target="_blank" rel="nofollow">SCNSceneSource類。上面的代碼中我們已經(jīng)看到了使用文件創(chuàng)建場景。

注意:為了獲得最佳效果,將應(yīng)用程序包中放置的場景文件放在帶有.scnassets擴展名的文件夾中,并將從這些場景引用的圖像文件作為紋理放置到Asset目錄中。然后,Xcode優(yōu)化場景和紋理資源,以便在每個目標設(shè)備上獲得最佳性能,并為delivery features(如App Thinning和On-Demand資源)準備。

B、你也可以使用該scene()方法創(chuàng)建一個空場景,并通過創(chuàng)建節(jié)點及其內(nèi)容的層次結(jié)構(gòu)將其添加為場景對象的子項來填充rootNode內(nèi)容。

②在我們場景中添加一個幾何體

? ? //創(chuàng)建空場景

? ? letscene = SCNScene()


? ? //創(chuàng)建一個六面體幾何模型,每面都為矩形,可選擇圓形邊緣和角,單位米

? ? letbox = SCNBox(width:0.1, height:0.1, length:0.1, chamferRadius:0);


? ? //創(chuàng)建節(jié)點 并將box加到節(jié)點上

? ? letboxNode = SCNNode(geometry: box)

? ? //設(shè)置節(jié)點位置。x,y,z軸位置

? ? boxNode.position = SCNVector3(0, 0, -0.2)


? ? //把節(jié)點添加到根節(jié)點上

? ? scene.rootNode.addChildNode(boxNode)

? ? //將場景設(shè)置到ARSCNView上顯示

? ? sceneView.scene = scene;

這里我們使用SCNBox來建立一個幾何體,運行效果如下圖

蘋果為我們內(nèi)置幾何類型不只SCNBox。還有基本形狀,如球體,框和平面,以及用于從2D文本和Bézier曲線生成3D對象的特征。點擊查看更多內(nèi)置幾何類型


大家看到會不會覺得~一個白茫茫的大方塊未免有些太丑陋了O_O

~~好讓我們先來點顏色瞧瞧

③渲染

渲染在電腦繪圖中是指用軟件從模型生成圖像的過程。模型是用嚴格定義的語言或者數(shù)據(jù)結(jié)構(gòu)對于三維物體的描述,它包括幾何、視點、紋理以及照明信息。

我們需要了解兩個類SCNMaterialProperty 和 SCNMaterial

A、SCNMatrialProperty(一種用于顏色或紋理的容器,用于材料的視覺特性之一)

材料具有幾種視覺特性,它們一起確定其在照明和陰影下的外觀。SceneKit通過將材料屬性的信息與燈的位置,強度和顏色相結(jié)合,渲染場景中的每個像素。

材料屬性的內(nèi)容可以是一種顏色,它可以通過材料的表面提供均勻的效果,或者紋理,SceneKit使用由材料所附加的幾何對象提供的紋理坐標來映射材料的表面。反過來,紋理可以來自任何幾個來源:

1.圖像對象,或圖像文件的路徑或URL

2.一個特殊格式的圖像或六個圖像的數(shù)組,用作立方圖

3.核心動畫層或?qū)訉哟谓Y(jié)構(gòu),其本身可能包含動畫內(nèi)容(Core Animation的layer對象)

4.提供靜態(tài)圖像的SpriteKit紋理,或渲染動畫2D內(nèi)容的整個SpriteKit場景。

B、接著給大家簡單的介紹另一個重要的類(SCNMaterial)

SCNMaterial是一組陰影屬性,用于定義渲染時幾何體表面的外觀。

創(chuàng)建材質(zhì)時,你可以定義一組視覺屬性及其選項,然后可以在場景中重復使用在多個幾何體上。

材料具有八個視覺屬性,列在“配置視覺屬性”中,每個都定義了SceneKit的照明和陰影處理的不同部分。每個視覺屬性都是類SCNMaterialProperty的一個實例,他為SceneKit的渲染方面提供了一個純色,紋理或其他2D內(nèi)容。材質(zhì)的屬性然后確定SceneKit用于將視覺特性與場景中的光合并以產(chǎn)生渲染場景中每個像素的最終顏色的公式。有關(guān)渲染過程的更多詳細信息,請參閱照明模型 lightingModel

你的SCNGeometry(幾種內(nèi)置幾何類型都繼承與本類)可以使用其firstMaterialmaterials將一個或多個材料附加到類的實例。多重幾何可以引用相同的材??料。在這種情況下,更改材質(zhì)的屬性會更改使用它的每個幾何體的外觀。

接下來我們先使用一下SCNMaterial中的一些配置視覺屬性

? ? //創(chuàng)建一個六面體幾何模型,每面都為矩形,可選擇圓形邊緣和角,單位米

? ? letbox = SCNBox(width:0.1, height:0.1, length:0.1, chamferRadius:0);


? ? //material渲染器

? ? letmaterial = SCNMaterial()

? //確定材質(zhì)的基礎(chǔ)顏色 - 幾何圖形,當白光照亮時,使用這種顏色的灰度顯示為陰影的材質(zhì)。如果您提供圖像,SceneKit將圖像映射到幾何圖形的表面,而不是使用均勻基色的陰影。

? ? //material.diffuse.contents = UIColor.orange

? ? material.diffuse.contents=UIImage(named:"brick")

? ? //如果幾何具有與幾何元素相同數(shù)量的材料,則材料索引對應(yīng)于元素索引。對于具有比元素少的材料的幾何,SceneKit通過計算該元素的材料數(shù)目的索引來確定每個元素的材料索引。例如,在具有六個元素和三個材質(zhì)的幾何體中,SceneKit將5使用索引處的材質(zhì)在索引處渲染元素5 % 3 = 2。

? ? box.materials = [material];


注:如果自己空白項目,要使用ARKit請使用應(yīng)用程序Info.plist, 設(shè)置UIRequiredDeviceCapabilities中的arkit鍵。如果增強現(xiàn)實是應(yīng)用程序的次要功能,請使用isSupported屬性來確定當前設(shè)備是否支持您要使用的會話配置。


(四)繼續(xù)探索~讓磚頭動起來~

1、嘗試用手勢讓磚塊動起來

廢話不多說直接上代碼

//添加手勢

func addGestureRecognizer() {

? ? //添加滑動手勢(用于移動和旋轉(zhuǎn)模型)

? ? let PanGestureRecognizer = UIPanGestureRecognizer(target:self, action:#selector(panFunc))

? ? sceneView.addGestureRecognizer(PanGestureRecognizer)

? ? //創(chuàng)建縮放手勢(用于縮放模型)

? ? let PinchGestureRecognizer = UIPinchGestureRecognizer(target:self, action:#selector(pinchFunc))

? ? sceneView.addGestureRecognizer(PinchGestureRecognizer)

}

//(用于移動和旋轉(zhuǎn)模型)

@objc func panFunc(recognizer:UIPanGestureRecognizer) {

? ? //1.獲取節(jié)點在空間中位置

? ? guard let node = self.sceneView.scene.rootNode.childNode(withName:"boxNode", recursively:true) else {

? ? ? ? return

? ? }

? ? let nodePosition = node.position

? ? //2.獲取相機當前在空間中位置

? ? guard let cameraTransform = self.sceneView.session.currentFrame?.camera.transform else {

? ? ? ? return

? ? }

? ? let translation = cameraTransform.columns.3

? ? //3.獲取本次滑動的距離

? ? let point = recognizer.translation(in:self.view)

? ? let pointX = Float(point.x / self.view.bounds.size.width) * 0.1

? ? let pointY = Float(point.y / self.view.bounds.size.height) * 0.1

? ? //4.設(shè)置新的位置 x(point.x+nodePosition.x)、y(-point.y+nodePosition.y)、z(point.y+nodePosition.z)

? ? let newNodePositionX = pointX + nodePosition.x;

? ? let newNodePositionY =? -pointY + nodePosition.y;

? ? let newNodePositionZ =? (translation.z-0.1 <? pointY+nodePosition.z)? ?? (translation.z-0.1)? :? (pointY + nodePosition.z);//模型z坐標保持在距離攝像頭0.1

? ? node.position = SCNVector3(newNodePositionX,? newNodePositionY,? newNodePositionZ)

? ? //旋轉(zhuǎn)使用

? //eulerAngles 具體參考 https://developer.apple.com/documentation/scenekit/scnnode/1407980-eulerangles

? ? let angles = Float((node.eulerAngles.x>6) ? (Float.pi/32) : (node.eulerAngles.x+Float.pi/32))

? ? node.eulerAngles = SCNVector3(angles, angles,0)

? ? recognizer.setTranslation(CGPoint.zero, in:self.view)

}

//縮放模型

var nodeBeganScale:Float!

@objc func pinchFunc(recognizer:UIPinchGestureRecognizer) {

? ? //1.獲取節(jié)點

? ? guard letnode = self.sceneView.scene.rootNode.childNode(withName:"boxNode", recursively:true) else {

? ? ? return

? ? }

? ? if recognizer.state == UIGestureRecognizerState.ended? {

? ? ? ? recognizer.scale = 1

? ? }? else? {

? ? ? ? //2.手勢開始時保存node的scale

? ? ? ? if recognizer.state == UIGestureRecognizerState.began {

? ? ? ? ? ? self.nodeBeganScale = node.scale.x

? ? ? ? }

? ? ? ? //3.縮放

? ? ? ? //CGAffineTransform轉(zhuǎn)換SCNVector3

? ? ? ? //轉(zhuǎn)換具體參考

? ? ? ? //CGAffineTransform矩陣運算的原理http://justsee.iteye.com/blog/1969933

? ? ? //node.scale SCNVector比例向量https://developer.apple.com/documentation/scenekit/scnnode/1408050-scale

? ? ? ? //這里我只是使用了x方向的縮放

? ? ? let nodeScale = Float(recognizer.view!.transform.scaledBy(x: recognizer.scale, y: recognizer.scale).a)? * self.nodeBeganScale

? ? ? ? node.scale = SCNVector3(nodeScale, nodeScale, nodeScale)

? }

}

效果圖

本章就到這里了,下節(jié)繼續(xù)為大家分享ARKit相關(guān)內(nèi)容,希望大家多多關(guān)注,感謝大家的到來。

本章的所有代碼: https://github.com/az52013141711/ARKit_ARSCNView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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