概述
iOS 11 引入了 ARKit房轿,這是一個全新的框架粤攒,允許開發(fā)者輕松地為 iPhone 和 iPad 創(chuàng)建無與倫比的增強現(xiàn)實體驗所森。通過將虛擬對象和虛擬信息同用戶周圍的環(huán)境相互融合,ARKit 使得應(yīng)用跳出屏幕的限制夯接,讓它們能夠以全新的方式與現(xiàn)實世界進行交互焕济。
視覺慣性測距【全局追蹤】
ARKit 使用視覺慣性測距 (Visual Inertial Odometry, VIO) 來精準追蹤周圍的世界。VIO 將攝像頭的傳感器數(shù)據(jù)同 Core Motion 數(shù)據(jù)進行融合盔几。這兩種數(shù)據(jù)允許設(shè)備能夠高精度地感測設(shè)備在房間內(nèi)的動作晴弃,而且無需額外校準。
場景識別與光亮估量【場景理解】
借助 ARKit逊拍,iPhone 和 iPad 可以分析相機界面中所呈現(xiàn)的場景上鞠,并在房間當中尋找水平面。ARKit 不僅可以檢測諸如桌子和地板之類的水平面芯丧,還可以在較小特征點 (feature points) 上追蹤和放置對象旗国。ARKit 還利用攝像頭傳感器來估算場景當中的可見光總亮度,并為虛擬對象添加符合環(huán)境照明量的光量注整。
高性能硬件與渲染優(yōu)化【渲染】
ARKit 運行在 Apple A9 和 A10 處理器上。這些處理器能夠為 ARKit 提供突破性的性能度硝,從而可以實現(xiàn)快速場景識別肿轨,并且還可以讓您基于現(xiàn)實世界場景,來構(gòu)建詳細并引人注目的虛擬內(nèi)容蕊程。您可以利用
Metal
椒袍、Scenekit
、Spritekit
以及諸如Unity
藻茂、UNREAL ENGINE
之類的第三方工具驹暑,來對 ARKit 進行優(yōu)化。
ARKit與SceneKit
- ARKit:相機捕捉真實世界
- Scenekit:制作3D模型
-
大家可以看到圖中的 ARSession 類辨赐,配置 ARSession优俘,然后使用 SceneKit 或者 SpriteKit 來展示 AR 內(nèi)容。ARSCNView 和 ARSKView 類都是包含在 ARSession 當中的掀序,而 ARSession 對象則用來管理設(shè)備動作追蹤和進行圖像處理的帆焕,也就是創(chuàng)建 AR 場景的必需品。但是不恭,要運行 Session叶雹,您首先必須選擇一種 Session 配置。
-
ARWorldTrackingConfiguration:提供高品質(zhì)的AR體驗换吧,可精確跟蹤設(shè)備的位置和方向折晦,并允許平面檢測和命中測試。
-
AROrientationTrackingConfiguration:提供僅跟蹤設(shè)備方向的基本AR體驗沾瓦。
然后满着,我們在這個配置上調(diào)用run()函數(shù)谦炒。該會話還具有同時運行的AVCaptureSession和CMMotionManager對象,以獲取用于跟蹤的圖像和運動數(shù)據(jù)漓滔。最后编饺,會話將當前幀輸出到ARFrame對象。
-
ARWorldTrackingConfiguration:提供高品質(zhì)的AR體驗换吧,可精確跟蹤設(shè)備的位置和方向折晦,并允許平面檢測和命中測試。
SCNScene:節(jié)點【萬物皆Scene】,每一個
Scene
都有個根節(jié)點RootNode
响驴。如圖所示節(jié)點類似于NSObject
,節(jié)點就可以看做是3D物件透且。
跟蹤設(shè)備方向的基本配置
ARFrame:捕獲和位置追蹤、視頻圖像信息豁鲤。
ARAnchor:一個真實的位置和方向,可用于將對象放置在一個基于“增大化現(xiàn)實”技術(shù)的游戲場景秽誊。
Tracking:如圖x、y琳骡、z三個軸組成锅论,z軸負數(shù)的情況下說明顯示在相機前面的位置,正數(shù)的時候顯示在相機后面的位置楣号。
AR應(yīng)用程序
如圖:
- ARKit負責采集場景最易;
- SceneKit、SpriteKit炫狱、Metal負責渲染藻懒;
- SpriteKit:在很久以前做平面、立體大家都要依靠OpenCV视译、OpenGL嬉荆,由于比較難用,后來有人封裝成cocos2d酷含。蘋果后來在cocos2d基礎(chǔ)上又封裝一層鄙早,也就是現(xiàn)在的SpriteKit。效果不錯后iOS8又推出了SceneKit椅亚;
- Metal:用來操作GPU限番;【GPU處理事情的時候是同步處理】
開發(fā)環(huán)境和適配設(shè)備
- Xcode:Xcode9以上版本,最新已更新到到 【Xcode9-beta 6】什往。
- 設(shè)備:需要具有A9或更高版本處理器的iOS設(shè)備扳缕。
- 系統(tǒng):當然是iOS11嘍,最新已更新到 【iOS 11 beta 9】,然后下載描述文件。安裝描述文件别威,重新啟動躯舔。檢查軟件更新就可以了。
項目創(chuàng)建
選擇SceneKit3D模型
工程創(chuàng)建后初始代碼
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// SCNScene:場景里面包含一個模型省古,然后把場景放到ARSCNView上粥庄,然后就可以展示。
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// Set the scene to the view
sceneView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// 通過`run()`啟動追蹤
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//通過`pause()`暫停
sceneView.session.pause()
}
真機直接運行
真機運行第一次會提示相機權(quán)限豺妓,開啟后顯示出一個3D飛機在相機前惜互。
下面我們創(chuàng)建一張相機截圖顯示在手機屏幕前
通過添加手勢布讹,點擊后生成截屏圖片顯示在手機前。
@objc func handtap(gestureRecognizer:UITapGestureRecognizer){
guard let currentFrame = sceneView.session.currentFrame else {
return
}
/// 創(chuàng)建圖片
let imagePlane = SCNPlane(width: sceneView.bounds.width / 6000, height: sceneView.bounds.height / 6000)
/// 渲染圖片
imagePlane.firstMaterial?.diffuse.contents = sceneView.snapshot() //截屏
imagePlane.firstMaterial?.lightingModel = .constant
/// 創(chuàng)建節(jié)點并添加到sceneView上
let planNode = SCNNode(geometry: imagePlane)
sceneView.scene.rootNode.addChildNode(planNode)
/// 追蹤相機位置
var translate = matrix_identity_float4x4
translate.columns.3.z = -0.1
///取相機里面的數(shù)據(jù)训堆,放到simdTransform
planNode.simdTransform = matrix_multiply(currentFrame.camera.transform, translate)
}
firstMaterial:渲染
sceneView.snapshot():sceneView全部內(nèi)容展示出來【截屏】
matrix_identity_float4x4:【4x4矩陣描验,x、y坑鱼、z膘流、高度的部分】
translate.columns.3.z = -0.1:追蹤的位置是在3軸的z軸-0.1的位置
運行結(jié)果
下面我們不用程序默認的模型,我們來創(chuàng)建自己的模型鲁沥,直接代碼走起
1. 創(chuàng)建一個盒子模型呼股,并進行渲染。
let scene = SCNScene()
/// 我們創(chuàng)建幾何模型:盒子
/// chamferRadius:圓角画恰,等于0時彭谁,說明是沒有圓角
let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
/// 創(chuàng)建節(jié)點,傳入幾何
let boxNode = SCNNode(geometry: box)
/// 對盒子進行渲染
/// 創(chuàng)建渲染器
/// material 渲染器
let material = SCNMaterial()
/// 渲染成紅色
//material.diffuse.contents = UIColor.red
/// 渲染一張照片
material.diffuse.contents = UIImage(named: "brick.png")
/// 渲染盒子
box.materials = [material]
/// 設(shè)置節(jié)點位置
/// SCNVector3:三維【x,y.z]
boxNode.position = SCNVector3(0,0,-0.2)
/// 把結(jié)點放到根節(jié)點上
scene.rootNode.addChildNode(boxNode)
sceneView.scene = scene
運行效果
2. 創(chuàng)建球體模型允扇,再點擊球體后缠局,進行不同圖片的渲染。
@IBOutlet var sceneView: ARSCNView!
let textures = ["earth.jpg","jupiter.jpg","mars.jpg","venus.jpg","IMG_0008.jpg"]
private var index = 1
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
let scene = SCNScene()
/// 我們創(chuàng)建幾何模型:球體
let sphere = SCNSphere(radius: 0.1)
/// 渲染
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "earth.jpg")
sphere.materials = [material]
/// 創(chuàng)建節(jié)點
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3(0,0,-0.5)
scene.rootNode.addChildNode(sphereNode)
sceneView.scene = scene
/// 創(chuàng)建手勢
registerGestureRecognizers()
}
func registerGestureRecognizers(){
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
self.sceneView.addGestureRecognizer(tapGestureRecognizer)
}
@objc func tapped (recognizer: UIGestureRecognizer){
/// 獲取ARSCNView
let sceneView = recognizer.view as! ARSCNView
/// 手勢點擊的位置
let touchLoaction = recognizer.location(in: sceneView)
/// 獲取點擊之后的結(jié)果
let hitRersults = sceneView.hitTest(touchLoaction, options: [:])
if !hitRersults.isEmpty {
if index == self.textures.count {
index = 0
}
guard let hitRersult = hitRersults.first else {
return
}
/// 更改渲染的圖片
let node = hitRersult.node
node.geometry?.firstMaterial?.diffuse.contents = UIImage(named: textures[index])
index += 1
}
}
運行效果