写点什么

iOS 开发 · iOS 音视频开发 - ARKit 教学:如何搭配 SceneKit 来建立一个简单的 ARKit Demo

用户头像
iOSer
关注
发布于: 19 小时前

目标

本教学主要会开发一个 ARkit Demo App,并应用 SceneKit 来协助你熟悉基础的 ARKit。


是时候让你开始沉浸在本篇教学内,并让你了解如何一步一步建构出 ARKit App,且透过你手上的装置与 AR 世界互动。


本篇教学的想法主要是学习 AR 与利用 API 来建置一个 APP,藉由教学的步骤,你将会一步步了解 ARKit 在实体装置上是如何与神奇的 3D 物件来互动的。


在开始前,请了解本篇教学仅是以基础功能应用为主。


作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的 iOS 交流群:1012951431,不管你是大牛还是小白都欢迎入驻 ,分享 BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

你需要准备的

进入本篇教学前,建议你已有对 iOS 的基础开发的能力,这属于中阶程度的教学,并且,我们将需要 Xcode9 以上的版本。


为了测试你的 ARKit App,你得需要一个可兼容 Apple 的 ARkit 的装置,建议有 Apple A9 处理器以上等级的装置。


现在请确认你已具备上述需求,并准备开始进行,以下是我将会带你走过:


  • 建立一个新的 ARKit apps 专案

  • 设定 ARKit SceneKit View

  • 将 ARSCNView 与 View Controller 结合

  • 连接 IBOutlet

  • 设定 ARSCNView Session

  • 允许相机使用权限

  • 将 3D 物件加到 ARSCNView

  • 加入手势判断功能到 ARSCNView

  • 从 ARSCNView 移除物件

  • 加入多样物件到 ARSCNView

建立一个新的 ARKit apps 专案

再来,打开 Xcode,在 Xcode 的菜单中,选择 File > New > Project… ,然后选择 Single View App 并按下next,其实 Xcode 也有内键 ARKit 的范例 App,但你仍可以使用 Single View App 来开发 AR app。



你可以自行命名你想要的专案名称,我是命名为 ARKitDemo,再按下 next 来完成新的专案。

设定 ARKit SceneKit View

现在请打开 Storyboard,请在右下角的 Object Library 找到 ARKit SceneKit View,将它拖拉至你的 View Controller。



然后将你的 ARKit SceneKit View 的尺寸拉满整个 View Controller,它应该会呈现如下方:



讚喔!这样的话,ARKit SceneKit View 就是我们要呈现扩增实境的 SceneKit 内容的位置。

连接 IBOutlet

我们目前仍在 Main.storyboard 位置,请往介面右上方找到toolbar,并开启Assistant Editor,现在将ARKit汇入到 ViewController.swift 档位置:


import ARKit
复制代码


接著请按住 control 并在 ARKit ScenKit 的 View 上拖到至ViewController.swift档,当连接到时,请指定为 IBOutlet,并命名为sceneView,对了,请放心地将didReceiveMemoryWarning()这个方法删除,我们不会在本篇教学使用到它。



设定 ARKit SceneKit View

想看看,若想要我们的 App 在一开始执行时就能透过相机看到真实世界,并能侦测我们的週遭环境,这其实是相当惊人的科技!如今 Apple 已经帮开发者建立一套扩增实境的功能,我们并不需要再多花时间从无到有的重新设计,所以,谢谢 Apple!让我们能拥抱 ARKit。


好的!现在是时候来设定 ARkit SceneKit View 了,请在 ViewController 的类别下插入下列程式码:


override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) let configuration = ARWorldTrackingConfiguration() sceneView.session.run(configuration)
}
复制代码


并在viewWillAppear(_:)方法内,我们将初始化 AR configuration,它称为ARWorldTrackingConfiguration,这是一个可以执行 world tracking 的功能设定,等等!你一定会问什麽是 world tracking?来看一下 Apple 的官方文件说明:


“World tracking 可提供装置上六个自由度轨迹,来找到场景所需的特徵点,world tracking 也会启用 performing hit-tests against the frame. 当这个单元暂停后,Tracking 将不会再执行。”

“World tracking provides 6 degrees of freedom tracking of the device. By finding feature points in the scene, world tracking enables performing hit-tests against the frame.Tracking can no longer be resumed once the session is paused.”

-Apple 官方文件


所以简单说明 world tracking 可以追踨装置的方位与位置,它也可以经由装置的相机来侦测真实世界的地平面。


最后一段程式码,AR 单元( Session)主要是管理动作追踨与相机影像处理内容。我们需要执行这个configuration


接下来,我们来加入另一个方法到ViewController内:


override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) sceneView.session.pause()
}
复制代码


viewWillDisappear(_:)方法中,我们主要做的是当 view 在关闭时,设定 AR 单元就会同时停止追踨动作与处理图像内容。


##允许相机使用权限


在我们要执行我们的 App 之前,我们需要告知我们使用者,我们得使用相机来进行扩增实境的应用,这是一个从 iOS10 就开始的必要询问告知动作,也因此,请打开 info.plist。然后在空白区域点选右键,并选择 Add row,在 key 下选用 Privacy –  Camera Usage Description,然后在 Value 下写下 For Augmented Reality



过来,请确认此时你已经做好刚刚所教的一切。


请拿起你的装置,并连线到你的 Mac,来第一次建立与执行在 Xcode 的专案,此时这个 App 将会询问你能否允许有打开相机的权限。请点按 OK。若选择 Don’t allow,代表 App 不能使用相机来做想要执行的事情。



现在你应该能够看到你相机画面了。


我们也算是设定好我们的 sceneView 单元,并能执行 world tracking,是时候进入令人兴奋的阶段了!扩增实境!


##将 3D 物件加到 ARSCNView


话不多说,直接进入扩增实境,我们将要一个立方体(box),那我们先将下列程式码加到你的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 公尺。


接下来,我们建立一个点位boxNode物件,这个点位可代表位置与一个物件在 3D 空间的座标,但对它自己而言,他本身不会有可以看到的内容,需要协助它添加资讯。


所以我们需要在这个点位来建立一个形状,并给予一些可视化的内容。先将立方体box的参数设为点位boxNode的几何资讯,我们再给我们的点位一个位置,然而这个位置和相机有关係,以正 x 轴而言,是右边;负 x 轴是左边,正 Y 轴是上方,负 Y 轴是下方,而正 Z 轴是往后,负 Z 轴是往前。


接著,我们要来建立一个场景,这是一个应用 SceneKit 的场景功能来显示在视图上,过来加入我们的boxNode做为场景的初始根点位,然而初始根点位在一个场景中,是 SceneKit 用来定义与真实世界的座标系统的方式。


正常来说,我们的场景现在会有了一个立方体了,这个立方体会位在相机画面的正中间,和相机的距离会有 0.2 公尺。


最后,让我们的 sceneView 来显示我们刚建立的场景。


现在请在viewDidLoad()加入addBox()的方法:


override func viewDidLoad() {
super.viewDidLoad() addBox()
}
复制代码


建立并执行这个 App,你应该可以看见一个飘浮在空中的立方体囉!



你现在也可以重新简化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)
}
复制代码


这会更容易了解在做些什麽事了吧。


好的!要继续加入手势了!


##加入手势辨识方法到 ARSCNView


addBox()的方法下,请加入下列程式码:


func addTapGestureToSceneView() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.didTap(withGestureRecognizer:))) sceneView.addGestureRecognizer(tapGestureRecognizer)
}
复制代码


在这裡,我们先初始化点击手势辨识方法物件,并将target设为ViewController,也就是self,在action内设为didTap(withGestureRecognizer:),然后我们再将点击手势辨识这个物件也加入在 scenView 内。


是时候来做些点击手势辨识方法物件内的呼叫方法


#从 ARSCNView 移除物件


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(withGestureRecognizer:)的方法,目的是我们要获得使用者在 sceneView 的点击位置,并可看得到我们触击的 node。


然后,我们将从hitTestResults中移除掉第一个点位,如果hitTestResults内没得到任何一个点位,我们将会当初第一个点击的点位,也是做为 parent node 的,就移除。


在我们测试物件移除时,请更新viewDidLoad()的方法,并加入一个呼叫addTapGestureToSceneView()的方法:


override func viewDidLoad() {
super.viewDidLoad()
addBox() addTapGestureToSceneView()
}
复制代码


现在如果你若能建置与执行你的专案,你应该可以点击 box node 并能从 scene view 移除它。


不过我们感觉回到了起点。


没关係!那我们来加多点物件。

加入多样物件到 ARSCNView

现在我们的立方体感觉有点孤独,我们也来多做一点立方体吧,我们将在一些特徵点上加入物件。


所以什麽是特徵点呢?


根据 Apple 官方说明,对特徵点的定义:


此点由 ARKit 自动从一个连续的表面中自动辨识,但不会有另一相对的依靠点。


它其实是依真实世界的实物表面上侦测特徵点,所以,我们回到如何实现增加立方体呢,在我们开始前,在 ViewController 类别的程式码最下方建立一个 extension。


extension float4x4 {
var translation: float3 { let translation = self.columns.3 return float3(translation.x, translation.y, translation.z) }
}
复制代码


这个 exetension 建立了一个float3的矩阵,它可同时加入 x, y 和 z 三个参数。


因此,我们下一步要修改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)
}
复制代码


基本上,我们加入了参数来初始化addBox()的方法,同时也给它一个初始值,这代表我们可以不用在viewDidLoad()呼叫addBox()的方法时,就得写入特定 x, y 和z 座标值。


好的!


现在我们需要修改didTap(withGestureRecognizer:)的方法,我们想要当真实世界的某一点被侦测到时,我们就能加入一个物件。


所以回到我们的guard let的程式码描述,在else之后,并在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) }}
复制代码


来解释我们想要达成的方式。


首先,我们先要有一个 hit test,很像是我们第一次测试,除了这个,我们清楚定义.featurePoint属于types


参数。types参数要求 hit test 经由 AR 单元的相机图像来搜寻真实世界的实体物或是表面。它内含许多类型,但本教学目前只针对特徵点。


经由特徵点的 hit test 后,我们可以安全地移除第一次 hit test 的结果,这观念很重要,因为不会一直都有特徵点,ARKit 并不会一会侦测真实世界的实体物与表面。


如果第一次 hit test 能成功移除,然后我们就将转换矩阵类型matrix_float4x4float3,因为我们之前已增加了一个 extension 来完成此功能,有兴趣的话,我们也可以自行修正 x, y 和z 实际世界座标。


然后,我们在一特徵点上输入 x, y 和 z 来加入一个立方体。


你的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()
}
复制代码

测试最终版 App

现在是时候按 Run 键执行项目以测试最终版的 App!



总结

恭喜你,和我们走了这麽久 完成本篇教学,ARKit 还有还有许多功能需要我们继续挑战,我们只是学了一些表面功夫。


我希望你享受本篇 ARKit 的介绍,我也期待你会建构出属于你的 ARKit App。


关于完整的范例专案,你可以在GitHub找到。

文末推荐:iOS 热门文集

用户头像

iOSer

关注

微信搜索添加微信 mayday1739 进微信群哦 2020.09.12 加入

更多大厂面试资料进企鹅群931542608

评论

发布
暂无评论
iOS开发 · iOS音视频开发 - ARKit 教学:如何搭配SceneKit来建立一个简单的ARKit Demo