拥有一个很棒的视觉感受可以让你的App有独特的个化风格,在这个教学中,我们将会了解一个创造3D物件工具,与相关线上资源可以支援SceneKit格式的3D物件,最重要的是,学习如何使用SceneKit建立一个基本简易的ARKit App。
事不宜迟,那我们先来试著在实境加入一些3D物件,我想应该会很有趣,我希望你将可以享受本篇教学,也感谢你分享本篇教学给予其他人了解。
当我们开始前,开发者还是需要一些基本知识,当然我们需要从之前的ARKit教学得到一些基础知识,如果你是第一次碰触ARKit,建议请先参考ARKit教学,来了解如何建立如何应用SceneKit来建立一个简易的ARkit。
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:1012951431,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!
你将会学习到的功能
好的!我们将会一起学习到很多功能,以下项目将是本教学会教给你的,包含:
- 简单介绍3D物件的工具与资源
- 如何实现一个单节点的3D物件
- 如何加入一个基本亮度
- 如何实现一个多节点的3D物件
如何建立或找到一个3D物件
要如何来建立或找到一个3D物件呢?请随著脚步来看看我们如何建立或找到相关资源。
建立3D物件工具
首先,你可以使用某些3D物件建立工具,来帮助你从无到有,建立属于你的3D模型,或是,你也可以使用这些工具组已有的3D模型,并能支援SceneKit的档案格式,我们等会会遇到更多的有关SceneKit支援格式的问题,如果你有计画建立属于你自己的3D物件,你可以参考下列这些工具:
3D物件相关线上资源
除了建立你自己的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装置和下图一样的画面:
请点选OK,你应该能够看到你自己的相机画面,下面就是当我用我的相机看到正在Apple store编写程式的画面:
实现一个单节点的3D物件
太棒了!是时候来添加一个单节点的3D物件到我们的ARSCNView,插入下列方法到ViewController
的类别中:
func addPaperPlane(x: Float = 0, y: Float = 0, z: Float = -0.5) {
guard let paperPlaneScene = SCNScene(named: "paperPlane.scn"), let paperPlaneNode = paperPlaneScene.rootNode.childNode(withName: "paperPlane", recursively: true) else { return }
paperPlaneNode.position = SCNVector3(x, y, z)
sceneView.scene.rootNode.addChildNode(paperPlaneNode)
}
在上述的程式码中,我们利用guard let
语法来安全执行来初始化以一个paperPlane.scn的SCNScene物件,这个档案已先行建立在我给的范例开发程式中。
接著,我们同样在guard let
下执行初始化以paperPlane节点的SCNNode物件,我们也将recursively
参数设为true
,recursively
的参数决定SceneKit是否要用前序搜寻法来找到子节点支干。
所有场景的内容 – 包含节点、地理资讯与他们的素材、亮度、相机与其他相关物件都依序层级放在一个根节点内。
-Apple官方文件
一但这个节点初始化,我们来设定paperPlaneNode
的方位,宣告x
、y
与z
,初始方位设定皆为0,表示这个方位会放在和一开始父节点同样的座标位置上,所以我会将z
设为-0,5
,代表此物件会在相机镜头的前方。
再来,我们将paperPlaneNode
加到sceneView
的rootNode
,也就是根节点上。
现在在viewDidLoad()
方法内来呼叫addPaperPlane(x:y:z:)
这个方法:
override func viewDidLoad() {
super.viewDidLoad()
addPaperPlane()
}
建立并执行在你的装置上,你将会看到一个白色的纸飞机!
此时,你会发现这个纸飞机有点看不清楚的感觉,这是因为缺少了亮度与阴影,在真实世界中,所有的事物都会有亮度与阴影组成,有了亮度与阴影,也造就了3D物件的视觉感受。
如果你从3D物件档案夹打开paperPlane.scn,你可以看见纸飞机是全白色的,所以它自然就没有很明显的视觉深度。
所以来加点亮度在我们的纸飞机上吧!
加入基本亮度
其实加入亮度的方式不只一种,这个专案中,我们将使用打开自动亮度模式与自动亮度提升。
所以在ViewController
的类别内,加入下列方法:
func configureLighting() {
sceneView.autoenablesDefaultLighting = true
sceneView.automaticallyUpdatesLighting = true
}
酷!我们刚做了:
- 一个
configureLighting()
的方法 - 在这个方法内,我们将
sceneView
的属性autoenablesDefaultLighting
设定为true
,如果autoenablesDefaultLighting
设定为true
,SceneKit将自动地增加亮度到这个场景中,技术上而言,SceneKit会感知所使用的场景没有亮度或是仅有些自有周围亮度时,将会开启全向光源。 - 下一步,我们将
sceneView
的属性automaticallyUpdatesLighting
设定为true
,如果将automaticallyUpdatesLighting
设定为true
,这个属性会自动从相机场景感知计算所需要的光度,若你想要自己控制亮度,你就得将此属性设为false
。
现在我们把configureLighting()
的方法嵌入viewDidLoad
的方法内:
override func viewDidLoad() {
super.viewDidLoad()
configureLighting()
addPaperPlane()
}
好极了!再次在你的装置上建置与执行专案,你应该可以看见一个具有美丽的曲线、造型与明显边界的纸飞机了!
此刻先静下心来,来爱上这个具有美丽的曲线、造型与明显边界的纸飞机吧。
实现多节点的3D物件
有些3D物件档案是含有多节点(Multiple Node)的特性,在这样的情境下,来看看我们如何加入一个具多节点的3D物件在我们的ARSCNView。
在3D物件档案夹内,有个car.dae的档案,如果你点击这个档案,你会在Xcode Scene Editor打开这个档案,你可以全部点选这个3D car物件的所有节点。
好的!现在请打开ViewController.swift
,插入下列的程式码在addPaperPlane(x:y:z:)
的方法下:
func addCar(x: Float = 0, y: Float = 0, z: Float = -0.5) {
guard let carScene = SCNScene(named: "car.dae") else { return }
let carNode = SCNNode()
let carSceneChildNodes = carScene.rootNode.childNodes
for childNode in carSceneChildNodes {
carNode.addChildNode(childNode)
}
carNode.position = SCNVector3(x, y, z)
carNode.scale = SCNVector3(0.5, 0.5, 0.5)
sceneView.scene.rootNode.addChildNode(carNode)
}
在上述程式码中,我们做了:
- 首先,我们建立一个以
car.dae
档案的SCNScene物件,并使用guard let
安全语法描述,然后我们初始化一个SCNNode物件,叫做carNode
。 - 接著,我们先设定一个
carSceneChildNodes
的变数来储存所有在carScene根节点下的子节点,过来,我们搜寻并加入carScene下所有的子节点,并加到carNode的子节点。 - 然后,我们设定CarNode的方位,CarNode的x、y和z资讯,将由
addCar
的宣告变数设定,然后我们设定缩放比例,皆为0.5。 - 最后我们将CarNode加入在SceneView的根节点。
现在先注解原有的addPaperPlane()
方法,并加入addCar()
方法于viewDidLoad()
方法内:
override func viewDidLoad() {
super.viewDidLoad()
configureLighting()
//addPaperPlane()
addCar()
}
再次建置并执行你的专案,你将会在你面前看到一台能漂浮在空中的车。
总结
恭喜你,能和我一起完成这个专案,希望你会喜欢这个专案。
为了能参考你做的功能是否有和我一样,你也可以从GitHub下载完整专案。