本文将会使用 ARKit 创建一个相当简单的 hello world AR app,结束时就可以在增强世界里放置 3D 立方体,并且可以用 iOS 设备绕着它移动。
要渲染 ARKit 中的 3D 内容,我会使用 SceneKit:https://developer.apple.com/scenekit/ 这是在 iOS 设备上渲染 3D 图形的框架。如果了解基础的 3D 概念,这玩意儿就相当简单了。
如果等不及看到文章最后,这是 app 的录屏。可以看到用 ARKit 可以在真实世界中放置虚拟物体,并且在移动摄像头时,这个物体会固定在空间中。
虽然这是一个非常简单的 app,我们在后面的文章中继续为其编写更多功能,包括几何检测、3D 物理和很多好玩的东西。
视频
准备
ARKit 目前仅支持 A9/A10 处理器的 iOS 设备。表示你需要一台 iPhone 6s 或以上的设备,当然也可以是 iPad 2017 款或以上的设备。
软件则需要安装:
- iOS 11 Beta:https://developer.apple.com/download/
- Xcode 9 Beta:https://developer.apple.com/download/
这样就准备就绪了。
创建项目
首先打开 Xcode,选择 ARKit 项目模板:
填上项目信息,确保 Content Technology 选项选择了 “SceneKit”。默认可能是 “SpriteKit”,这是用来做 2D 渲染的,我们需要的是 “SceneKit”,这才是用于 3D 渲染的。
在你的设备上运行项目,如果没有异常的话应该能看见实时摄像头视频,还有一架飞机的 3D 模型,这个模型被放置在了物理空间中。
来回移动,看看飞机是如何固定在真实世界中的:
这个初始项目中的例子其实比马上要创建的项目更高级,但重点是学习如何从头编写 ARKit 项目,所以打开项目,移除 viewDidLoad 方法中所有的代码(除了 super 调用的那句)。
ARKit 核心类
ARSCNView——这是一个助手类,帮我们用 SceneKit 渲染的 3D 内容来增强实时摄像头视图。这个类做了下面几件事:
- 在视图中渲染设备摄像头的实时视频流,并就其设置为 3D 场景的背景
- ARKit 的 3D 坐标系会匹配 SceneKit 的 3D 坐标系,所以此视图渲染的对象会自动匹配增强后的 ARKit 世界视图
- 自动移动虚拟 SceneKit 3D 摄像头来匹配 ARKit 追踪到的 3D 位置,所以不需要再写代码连接 ARKit 移动事件与 SceneKit 3D 渲染。
ARSession——每个增强现实会话都都需要有一个 ARSession 实例。它负责控制摄像头、聚合所有来自设备的传感器数据等等以构建无缝体验。ARSCNView 实例已经有 ARSession 实例,只需要在开始的时候配置一下。
ARWorldTrackingSessionConfiguration——这个类会告诉 ARSession,在真实世界中追踪用户时需要使用六个自由度,roll、pitch、yaw 以及 X轴、Y轴、Z轴上的变换。如果不用这个类,就只能创建在同一个点旋转查看增强内容的 AR 体验。有了这个类,就可以在 3D 空间里绕着物体移动了。如果你不需要在 X轴、Y轴、Z轴上的变换,用户就会在投影增强内容时保持在固定位置,这时可以用 ARSessionConfiguration 类替代此类来初始化 ARSession 实例。
本文仅需使用这三个类,当然 ARKit 还有很多类,但我们才刚起步,这些就足够了。回到项目,可以看到在 viewWillAppear 方法中初始化了 ARSession 实例,self.sceneView 指向一个 ARSCNView 实例。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingSessionConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
绘制立方体
下面我要用 SceneKit 来绘制 3D 立方体。SceneKit 有一些基础类,SCNScene 是所有 3D 内容的容器,可以向其添加多个 3D 几何体,分别是不同的位置、旋转、缩放等等。
要向 scene 中添加内容,首先要创建 Geometry,geometry 可以是负责的形状,也可以是简单的形状如球、立方体、平面等等。然后将 geometry 包装为 scene node 并将其添加到 scene 中。然后 SceneKit 会遍历 scene graph 并渲染内容。
为了添加 scene 并绘制立方体(cube), 需要在 viewDidLoad 方法里添加如下代码:
override func viewDidLoad() {
super.viewDidLoad()
// 存放所有 3D 几何体的容器
let scene = SCNScene()
// 想要绘制的 3D 立方体
let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.0)
// 将几何体包装为 node 以便添加到 scene
let boxNode = SCNNode(geometry: boxGeometry)
// 把 box 放在摄像头正前方
boxNode.position = SCNVector3Make(0, 0, -0.5)
// rootNode 是一个特殊的 node,它是所有 node 的起始点
scene.rootNode.addChildNode(boxNode)
// 将 scene 赋给 view
sceneView.scene = scene
}
ARKit 中的坐标单位为米,所以我们就创建了一个 10x10x10 厘米的盒子。
ARKit 和 SceneKit 的坐标系看起来就像这样:
因为摄像头面对负 Z 轴方向,所有上面的代码就是把 box 置于摄像头前 -0.5 单位。
ARSession 开始时,摄像头 position 被初始化为 X=0, Y=0, Z=0。
如果现在运行此例,应该可以看见浮在空中的小小 3D 立方体,尝试绕着它走动,它还会保留原处。它应该是全方位无死角的,哪怕从下面、从上面看过去。
如果想在 3D 场景中添加一些默认光照以便看清立方体的边缘,可以设置 SCNScene 实例的 autoenablesDefaultLighting 属性:
sceneView.autoenablesDefaultLighting = true
后面的文章里会为它添加更高级的光照。
示例代码
所有的示例代码都在这里:https://github.com/josephchang10/ARCube
下篇文章
下篇文章会让这个 app 更好玩,添加几个更复杂的对象、检测场景中的平面还有与场景中的几何体交互,保持联系!