拥有一个很棒的视觉感受可以让你的App有独特的个化风格,在这个教学中,我们将会了解一个创造3D物件工具,与相关线上资源可以支援SceneKit格式的3D物件,最重要的是,学习如何使用SceneKit建立一个基本简易的ARKit App。

事不宜迟,那我们先来试著在实境加入一些3D物件,我想应该会很有趣,我希望你将可以享受本篇教学,也感谢你分享本篇教学给予其他人了解。

当我们开始前,开发者还是需要一些基本知识,当然我们需要从之前的ARKit教学得到一些基础知识,如果你是第一次碰触ARKit,建议请先参考ARKit教学,来了解如何建立如何应用SceneKit来建立一个简易的ARkit。

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

你将会学习到的功能

好的!我们将会一起学习到很多功能,以下项目将是本教学会教给你的,包含:

  • 简单介绍3D物件的工具与资源
  • 如何实现一个单节点的3D物件
  • 如何加入一个基本亮度
  • 如何实现一个多节点的3D物件

如何建立或找到一个3D物件

要如何来建立或找到一个3D物件呢?请随著脚步来看看我们如何建立或找到相关资源。

建立3D物件工具

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图1

首先,你可以使用某些3D物件建立工具,来帮助你从无到有,建立属于你的3D模型,或是,你也可以使用这些工具组已有的3D模型,并能支援SceneKit的档案格式,我们等会会遇到更多的有关SceneKit支援格式的问题,如果你有计画建立属于你自己的3D物件,你可以参考下列这些工具:

3D物件相关线上资源

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图2

除了建立你自己的3D物件外,你也许会使用一些需能立即选用或得付费的3D模型放在你的ARKit App中,这儿有些线上资源应该对你有些帮助:

可支援SceneKit格式

我们会使用SceneKit来建立ARKit App。为了能在ARKit App上读取3D物件,理所当然地,你的3D物件档案格式必须支援SceneKit,这样Xocde才能读懂你的物件。

SceneKit需在能支援的格式下才能读取场景内容,或是能支援NSData物件的档案

Apple官方说明

在本篇教学中,我们将会使用SceneKit Scene (.scn)Digital Asset Exchange (.dae)档案支援格式在SceneKit上。

从范例专案开始

首先,请先下载范例专案,我已建立这个App的基本架构并加入两个3D档案,所以我们更可以专注在ARkit的开发,一旦下载后,请打开Xcode,并先执行测试一下。

你应该可以在你的iOS装置和下图一样的画面:

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图3

请点选OK,你应该能够看到你自己的相机画面,下面就是当我用我的相机看到正在Apple store编写程式的画面:

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图4

实现一个单节点的3D物件

太棒了!是时候来添加一个单节点的3D物件到我们的ARSCNView,插入下列方法到ViewController的类别中:

  1. func addPaperPlane(x: Float = 0, y: Float = 0, z: Float = -0.5) {
  2. guard let paperPlaneScene = SCNScene(named: "paperPlane.scn"), let paperPlaneNode = paperPlaneScene.rootNode.childNode(withName: "paperPlane", recursively: true) else { return }
  3. paperPlaneNode.position = SCNVector3(x, y, z)
  4. sceneView.scene.rootNode.addChildNode(paperPlaneNode)
  5. }

在上述的程式码中,我们利用guard let语法来安全执行来初始化以一个paperPlane.scnSCNScene物件,这个档案已先行建立在我给的范例开发程式中。

接著,我们同样在guard let下执行初始化以paperPlane节点的SCNNode物件,我们也将recursively参数设为truerecursively的参数决定SceneKit是否要用前序搜寻法来找到子节点支干。

所有场景的内容 – 包含节点、地理资讯与他们的素材、亮度、相机与其他相关物件都依序层级放在一个根节点内。

-Apple官方文件

一但这个节点初始化,我们来设定paperPlaneNode的方位,宣告xyz,初始方位设定皆为0,表示这个方位会放在和一开始父节点同样的座标位置上,所以我会将z设为-0,5,代表此物件会在相机镜头的前方。

再来,我们将paperPlaneNode加到sceneViewrootNode,也就是根节点上。

现在在viewDidLoad()方法内来呼叫addPaperPlane(x:y:z:)这个方法:

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. addPaperPlane()
  4. }

建立并执行在你的装置上,你将会看到一个白色的纸飞机!

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图5

此时,你会发现这个纸飞机有点看不清楚的感觉,这是因为缺少了亮度与阴影,在真实世界中,所有的事物都会有亮度与阴影组成,有了亮度与阴影,也造就了3D物件的视觉感受。

如果你从3D物件档案夹打开paperPlane.scn,你可以看见纸飞机是全白色的,所以它自然就没有很明显的视觉深度。

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图6

所以来加点亮度在我们的纸飞机上吧!

加入基本亮度

其实加入亮度的方式不只一种,这个专案中,我们将使用打开自动亮度模式与自动亮度提升。

所以在ViewController的类别内,加入下列方法:

  1. func configureLighting() {
  2. sceneView.autoenablesDefaultLighting = true
  3. sceneView.automaticallyUpdatesLighting = true
  4. }

酷!我们刚做了:

  • 一个configureLighting()的方法
  • 在这个方法内,我们将sceneView的属性autoenablesDefaultLighting设定为true,如果autoenablesDefaultLighting设定为true,SceneKit将自动地增加亮度到这个场景中,技术上而言,SceneKit会感知所使用的场景没有亮度或是仅有些自有周围亮度时,将会开启全向光源。
  • 下一步,我们将sceneView的属性automaticallyUpdatesLighting设定为true,如果将automaticallyUpdatesLighting设定为true,这个属性会自动从相机场景感知计算所需要的光度,若你想要自己控制亮度,你就得将此属性设为false

现在我们把configureLighting()的方法嵌入viewDidLoad的方法内:

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. configureLighting()
  4. addPaperPlane()
  5. }

好极了!再次在你的装置上建置与执行专案,你应该可以看见一个具有美丽的曲线、造型与明显边界的纸飞机了!

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图7

此刻先静下心来,来爱上这个具有美丽的曲线、造型与明显边界的纸飞机吧。

实现多节点的3D物件

有些3D物件档案是含有多节点(Multiple Node)的特性,在这样的情境下,来看看我们如何加入一个具多节点的3D物件在我们的ARSCNView。

在3D物件档案夹内,有个car.dae的档案,如果你点击这个档案,你会在Xcode Scene Editor打开这个档案,你可以全部点选这个3D car物件的所有节点。

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图8

好的!现在请打开ViewController.swift,插入下列的程式码在addPaperPlane(x:y:z:)的方法下:

  1. func addCar(x: Float = 0, y: Float = 0, z: Float = -0.5) {
  2. guard let carScene = SCNScene(named: "car.dae") else { return }
  3. let carNode = SCNNode()
  4. let carSceneChildNodes = carScene.rootNode.childNodes
  5. for childNode in carSceneChildNodes {
  6. carNode.addChildNode(childNode)
  7. }
  8. carNode.position = SCNVector3(x, y, z)
  9. carNode.scale = SCNVector3(0.5, 0.5, 0.5)
  10. sceneView.scene.rootNode.addChildNode(carNode)
  11. }

在上述程式码中,我们做了:

  • 首先,我们建立一个以car.dae档案的SCNScene物件,并使用guard let安全语法描述,然后我们初始化一个SCNNode物件,叫做carNode
  • 接著,我们先设定一个carSceneChildNodes的变数来储存所有在carScene根节点下的子节点,过来,我们搜寻并加入carScene下所有的子节点,并加到carNode的子节点。
  • 然后,我们设定CarNode的方位,CarNode的x、y和z资讯,将由addCar的宣告变数设定,然后我们设定缩放比例,皆为0.5。
  • 最后我们将CarNode加入在SceneView的根节点。

现在先注解原有的addPaperPlane()方法,并加入addCar()方法于viewDidLoad()方法内:

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. configureLighting()
  4. //addPaperPlane()
  5. addCar()
  6. }

再次建置并执行你的专案,你将会在你面前看到一台能漂浮在空中的车。

iOS开发 · iOS音视频开发 - ARKit教学:学习如何在实境加入一个虚拟3D物件 - 图9

总结

恭喜你,能和我一起完成这个专案,希望你会喜欢这个专案。

为了能参考你做的功能是否有和我一样,你也可以从GitHub下载完整专案

文末推荐:iOS热门文集