开始学习如何制作第一个ARKit应用程序

苹果的ARKit API使每个iOS开发人员都可以使用令人兴奋的增强现实世界,但是您从哪里开始呢? 与我们一起进行增强现实之旅,构建AR太阳系,并学习如何制作您的第一个ARKit应用程序。

这篇文章来自ARKit的多部分系列,我们讨论AR的设计,构建演示应用程序,探索和测试ARKit的许多功能。 我们之前曾写过关于 为AR应用程序设计3D模型的文章

介绍

AR是神奇的应用程序(如神奇宝贝Go,Snapchat的动画表情符号和Instagram的3D贴纸)背后的核心技术。 苹果在2017年WWDC上宣布了ARKit,已经产生了一些令人印象深刻的软件,结合了有趣和实用的应用程序,为每个人提供了一些东西。 我们希望有机会尝试使用它,看看我们可以用它构建什么令人难以置信的东西。

在过去的一年中,Novoda一直在研究ARKit的功能,了解我们可以构建的内容以及该技术的局限性,我们用它来构建内容有很多乐趣,并希望分享一些发现。

他们说,将房屋设置为帽子是测试位置的最佳方法

在本演示中,我们将使用在本系列的设计部分中创建的自定义3D模型。 即使您无法创建自己的自定义模型,也可以使用Apple提供的简单AR多维数据集或从SketchUp或Google的Poly下载模型

首先要了解的是AR如何通过设备相机感知世界:它将AR相机输入转换成由平面,光源,虚拟相机和特征点组成的场景。

ARKit识别场景图像中的显着特征,跟踪这些特征在视频帧中的位置差异,并将该信息与运动感应数据进行比较。 结果是设备位置和运动的高精度模型,该模型还可以分析和理解场景的内容。

如果您想进行更深入的分析,我强烈建议您阅读此页面Apple的About Augmented Reality或在ARKit上观看他们的WWDC 2017演讲。 我还建议您观看WWDC 2018的《了解ARKit跟踪和检测》演讲以及ARKit2视频。

带有平面和光源的模型在Xcode上的外观。 这将被添加到AR场景中

通过此世界跟踪和平面检测,ARKit可以创建特征点 ,ARKit中使用了特征点将模型放置在场景中,并将模型锚定在其“周围”环境中。 如Apple所述:

这些点代表在相机图像中检测到的显着特征。 它们在3D世界坐标空间中的位置被推断为ARKit执行的图像分析的一部分,以便准确跟踪设备的位置,方向和运动。 总而言之,这些点从摄像机的角度松散地与实际对象的轮廓相关。

使用ARView和ARSCNView

为了构建AR应用程序,我们遵循了一系列教程AppCode ARKit简介,带有3D对象的AppCoda ARKit,由示例创建的带有ARKit和MarkDaws AR的Pusher构建AR,以及Apple提供的有关AR类的文档。 由于Apple和其他教程已经介绍了大多数基本设置,因此我们不会在此处发布所有代码,而仅介绍我们在此过程中发现的一些逻辑,问题和解决方案。 与此项目相关的所有源代码以及以下所有与此项目相关的文章都可以在我们的GitHub上找到。

创建ARKit项目时首先要做出的决定是使用标准的单视图应用模板还是Apple提供的AR模板。 我们都尝试过这两种方法,但在简单的应用程序/演示中几乎没有什么区别。 AR模板设置为使用情节ARSCNView ,并具有带有飞机模型的预配置ARSCNView 。 如果您喜欢在编写自己的代码之前先试用工作代码,我们建议您使用AR模板,尤其是它带有一些清晰的解释性注释。 另外,如果您希望控制每段代码,那么从头开始显然更好。 在此演示中,我们使用了模板和情节提要,但是即使您从头开始创建项目,您也应该能够继续进行。

每个AR应用程序都需要一些关键点:

  • 您将需要ARSCNView 。 大多数人将其实例命名为sceneView 。 这是所有AR魔术发生的地方。 您可以将其设置为占据整个屏幕或仅作为UI的一部分。
  • 您需要实现ARSCNViewDelegate协议,该协议包括用于将模型呈现到View中的方法。 sceneView控制器将实现此协议,并成为View的委托。
 sceneView.delegate = self 
  • 需要使用所需的平面跟踪类型(默认为水平)来设置ARConfiguration ,然后将其添加到sceneView会话run()方法中以实际启动AR场景。 ARSession
  • viewWillDisappear我们暂停了sceneView会话,以停止在AR运行时对手机执行的世界跟踪和设备运动跟踪。 这使设备可以释放资源。

启用了“调试中的特征点”选项后,您可以在围绕飞机(又称为黄点)移动时看到ARKit识别的内容

现在开始有趣的部分:将3D模型添加到sceneView ! 不用创建带有资产的场景,您可以创建一个SCNNode然后将该节点放在特定点的sceneView上。 我们在这里使用节点而不是SCNScene因为SCNScene对象占据了整个sceneView ,但是我们希望模型在场景的特定点上。

要创建SCNode,我们首先使用资产加载临时SCNScene,然后将场景的childNode保存为我们将要使用的节点。 我们这样做是因为您无法使用资产初始化节点,但是如果您通过名称搜索节点,则可以从加载的场景中加载节点。

如何在场景中设置节点名称

获取节点后,下一步就是将其添加到场景中。 我们发现了两种不同的实现方式,选择一种或另一种取决于您希望应用程序如何工作。

首先,我们需要知道在3D世界中将模型渲染到何处。 对于我们的演示,我们通过从touchesBegan方法中点击用户CGpoint来获得位置:

从用户获取最接近2D触摸位置的AR点

使用worldTransform方法获取位置CGPoint并将其转换为float_4x4矩阵。

从上面的示例中获得的location变量是一个2D点,​​我们需要将其定位在3D AR场景中。 这就是上面提到的功能点发挥作用的地方。 通过查找最接近抽头位置的特征点,将其用于外推锚点的z坐标。

 sceneView.hitTest(location, types: .featurePoint) 

您还可以使用案例.existingPlaneUsingExtent.estimatedHorizontalPlane来获取使用planeDetection时飞机的位置

此方法为我们提供了最接近的ARHitTestResult数组, ARHitTestResult与抽头位置的距离增加排序。 因此,该数组的第一个结果是最接近的点。 然后我们可以使用以下内容
let transformHit = hit.worldTransform返回2D接触点的真实世界位置的float4x4矩阵。

平面检测

现在我们有了3D世界中触摸的位置,我们可以使用它来放置对象了。 我们可以通过两种不同的方式将模型添加到场景中,一种选择另一种取决于我们如何设置ARSession以及是否启用了planeDetection 。 这是因为如果您在启用planeDetection运行配置,以进行水平或垂直检测,则ARSCNView将连续检测环境并将任何更改呈现到sceneView

当您运行 启用了 planeDetection 选项 的世界跟踪AR会话时 ,该会话会自动将 ARKit使用后置摄像头检测到的每个平面 ARPlaneAnchor 对象 添加到其锚列表中 每个平面锚提供有关估计的表面位置和形状的信息。

ARWorldTrackingConfiguration添加到ARWorldTrackingConfiguration时,我们可以在viewWillAppear上启用ARSession

 configuration.planeDetection = .horizontal 

因此,当planeDetection ,我们可以通过从场景对象创建新的SCNode并将节点的位置SCNVector3为我们希望模型在视图上的位置,从而将新节点添加到场景中。 然后,我们将该节点添加为sceneViewchildNode的一部分,并且由于启用了planeDetection ,AR框架将自动拾取新的锚并将其呈现在场景上。

使用获取3D位置的相同方法,我们将之前创建的节点添加到sceneView

尝试查找放置模型的位置时,可以使用.existingPlaneUsingExtent.estimatedHorizontalPlane案例,而不使用.estimatedHorizontalPlane案例。 在每种情况下,给出的结果都将有所不同,并且取决于您要放置对象的位置和方式。 现有平面将为您提供在平面(例如地板或桌子)上的点固定,而特征点将在实际环境中跟踪物体时为物体周围提供更特定的位置。

为了获得正确的节点位置,我们将需要使用我们之前创建的finalTransform float4x4矩阵并将其转换为float3 。 为此,我们使用了一个扩展程序,将我们的float4x4矩阵转换为float3

将4×4矩阵转换为float3的转换扩展

Tada🎉我们刚刚将3D模型成功添加到AR场景中!

锚定

让应用程序连续检测飞机会占用大量资源。 Apple建议您在完成场景检测后禁用planeDetection 。 但是正如我们之前提到的,如果未启用ARScene ,则planeDetection不会选择新添加的childNode并将其呈现到sceneView

因此,如果您希望在完成检测平面之后能够向场景添加新的节点和模型,则需要手动添加一个新的ARAnchor

为了从抽头位置创建ARAnchor ,我们将使用之前创建的相同transformHit float4x4矩阵-这次无需转换,因为ARAnchorsARHitResults使用相同的坐标空间。

将锚点添加到场景以渲染对象

通过自己添加新的锚点,而不是依赖于会话配置,我们从委托中触发renderer()函数,该函数将为特定锚点返回要渲染的节点。

通过render方法将节点添加到锚点

我们需要仔细检查触发渲染函数的锚点是否只是我们刚刚添加的锚点,而不是ARPlaneAnchor

有了这个位置,我们的模型将在planeDetection的轻敲位置进行渲染, planeDetection启用了planeDetection一样无缝。

Tada🎉我们刚刚将3D模型成功添加到AR场景中!

结论

总而言之,在本文中,我们介绍了增强现实和苹果公司的ARKit的基础。 我们借鉴了经验教训,并制作了一个应用程序,使用两种不同的方法将3D模型添加到世界上。

该演示的代码可以在Novoda的GitHub上找到,您也可以检查我们的ARDemoApp回购,在这里您可以编写自己的模型到AR Scene中,而无需编写任何代码。

如果您喜欢这篇文章,请务必检查本系列的其余部分!

有什么意见或问题吗? 让我们在Twitter @bertadevant上 @KaraviasD