前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >平面检测-搜索真实世界的表面

平面检测-搜索真实世界的表面

作者头像
iOSDevLog
发布2019-06-17 14:42:47
2.9K0
发布2019-06-17 14:42:47
举报
文章被收录于专栏:iOSDevLog

现在我们已经完成了正确运行ARKit项目的所有基本设置,我们希望我们的设备能够坐在水平表面上。这是飞机检测。在本节中,我们将学习如何激活平面检测。我们将熟悉锚点以及如何使用它们将对象放置在锚点上。此外,我们将能够在现实生活中看到我们发现的飞机锚。从现在开始,我们将更多地投入到代码中。

下载

要学习本教程,您需要Xcode 10或更高版本,以及来自Configuration for ARKit的最终Xcode项目。您可以下载本节的最终Xcode项目,以帮助您与自己的进度进行比较。

水平平面检测

首先,我们需要打开配置的平面检测属性并将其设置为水平,以检测平面(如地板或桌子)。在配置声明下面写:

代码语言:javascript
复制
configuration.planeDetection = .horizontal

ARSCNViewDelegate

ViewController类中,添加了一个委托ARSCNViewDelegate,以允许视图在渲染场景时接收信息。ARSCNViewDelegate是一种协议,它包含许多方法来帮助跟踪摄像机视图中的对象。方法就像程序或例程来实现某些东西。

在编程中,委托是一种设计模式,允许类将其职责委托给另一个对象。换句话说,就像要求别人为你做一份工作。在我们的例子中,ViewController将自己指定为ARSCNView的委托,委托者,从场景视图中检索内容的任务,管理其更新并处理其事件。

代码语言:javascript
复制
sceneView.delegate = self

一旦执行了任务,代表就会将信息报告回场景视图。

为了更多地了解Swift中的委派,我邀请您访问或查看本书第4章中的委托部分。

扩展课程

为了保持井井有条,让我们创建一个新文件来托管与ARSCNViewDelegate相关的所有代码。右键单击ViewController.swift并选择新建文件...。然后,在Source下选择Swift File,点击Next。将其命名为ViewController + ARSCNViewDelegate,然后命名为Create

导入套件

一旦创建了新的Swift文件ViewController + ARSCNViewDelegate.swift,就会自动导入Foundation框架。它是我们不需要的应用程序的基础框架。请改为使用以下框架替换它。

代码语言:javascript
复制
import SceneKit
import ARKit

延期

这个文件将作为ViewController类的扩展,这里的代码将成为该类的一部分。为表明这一意图,请写下:

代码语言:javascript
复制
extension ViewController: ARSCNViewDelegate {
}

将显示错误消息:“ViewController”与协议“ARSCNViewDelegate”的冗余一致性。那是因为我们已经在同一个类中采用了ARSCNViewDelegate。在ViewController.swift文件中,将其删除。当我们在它时,向下滚动并删除Mark下的注释掉的代码,这是该协议下的一个方法的给定示例。Mark帮助我们分离文件中的代码段。

添加锚点

让我们回到ViewController + ARSCNViewDelegate.swift。现在,让我们从ARSCNViewDelegate实现一个新方法来查找表面。键入didAdd并在选项中选择渲染器。该didAdd方法当相机检测到物体会通知我们,然后标记的它。一个是类型的ARAnchor给出关于跟踪的对象的位置,取向和尺寸信息。ARAnchor有意用于在场景上放置虚拟对象。然后为该锚分配一个简称为节点SCNNode

代码语言:javascript
复制
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
}

平面锚点

我们不想要任何对象,更具体地说我们想要搜索平面。如果跟踪的对象是平面,让我们进行场景测试。从技术上讲,如果锚是一个ARPlaneAnchor

代码语言:javascript
复制
if anchor is ARPlaneAnchor {
    print("Horizontal surface detected")
} else {
    return
}

如果确实如此,请在控制台“检测到水平表面”中打印以告知我们。否则,返回或退出方法。运行该应用程序以测试它。

返回委托文件,为planeAnchor声明一个常量。我们将使用它作为锚点来放置对象。

代码语言:javascript
复制
let planeAnchor = anchor as! ARPlaneAnchor

这意味着如果是平面,则将其类型转换为平面锚

平面节点

当我们运行应用程序时,我们可以在调试区域中看到找到水平表面时。但是在屏幕上看到它不是很好吗?为此,我们将添加一个函数来创建一个节点作为我们的视觉辅助。

代码语言:javascript
复制
func createPlane(planeAnchor: ARPlaneAnchor) -> SCNNode {}

该函数有一个名为参数planeAnchorARPlaneAnchor就像在不断didAdd方法。该函数将返回一个SCNNode,如右箭头所示。所以基本上,它输入一个平面锚并输出一个节点。

你应该在一个函数中错误地返回一个预期返回'SCNNode'的函数中的Missing return。不要担心,我们将继续编写代码并在最后添加缺少的返回值。

平面几何

在此函数中,我们将为节点设置几何,并且该几何是平面。因此,使用其范围属性创建一个大小为planeAnchor的平面。

代码语言:javascript
复制
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))

在这里,我们假设高度将被指定为y的范围。但是你看文档,y向量不存在,而z是要使用的。

您应该看到推荐的修复程序出现错误。只需单击Fix即可将Float类型的x extent值转换为CGFloat。为y做同样的事情。

接下来,让我们为飞机赋予纹理。我们将使用网格图像。

代码语言:javascript
复制
plane.firstMaterial?.diffuse.contents = UIImage(named: "grid")

然后,使用平面的几何创建一个名为planeNode的节点。

代码语言:javascript
复制
let planeNode = SCNNode(geometry: plane)

到现在为止,您应该已经识别出材料漫反射这两个词。你在Scene Editor中看过它。您现在正在学习如何在代码中应用它。

飞机位置

所以,就像我们为手表所做的步骤一样,我们需要定位它。将平面节点放在检测到的曲面的中心

代码语言:javascript
复制
planeNode.position = SCNVector3(planeAnchor.center.x, planeAnchor.center.y, planeAnchor.center.z)

最后,此函数需要在调用时返回一个值。

代码语言:javascript
复制
return planeNode

添加平面节点

回到didAdd方法,让我们调用该函数。

代码语言:javascript
复制
let planeNode = createPlane(planeAnchor: planeAnchor)

然后,将planeNode作为表示平面的节点的子节点。

代码语言:javascript
复制
node.addChildNode(planeNode)

运行应用程序以查看网格。

修复平面节点

检查网格时,您应该会看到一些问题。首先,网格是立起来的,另一个问题是你只能看到飞机一侧的网格。这是我们需要解决的两个问题。

好吧,还记得在我们第一次拖动飞机作为屏幕时的手表场景吗?它的默认方向是垂直的。嗯,这里也是如此。所以我们需要将它旋转90度。但是,Swift将角度存储在弧度中。如何将度数转换为弧度?我们应该回顾一下我们的高中数学。为了找到弧度的等价物,这里是等式。

根据图表,你会得到90度是pi的一半。在函数createPlane中,我们将在x轴上旋转网格以使其成为水平。也要顺时针旋转,在前面添加一个减号。

代码语言:javascript
复制
planeNode.eulerAngles.x = -.pi / 2

但严重的是,谁有时间甚至想要计算和转换度数和弧度?幸运的是,Swift有一个功能,GLKMathDegreesToRadians,所以利用它。注释掉前一行代码并替换为此代码。

代码语言:javascript
复制
planeNode.eulerAngles.x = GLKMathDegreesToRadians(-90)

此外,使网格图像覆盖平面的两侧以解决第二个问题。

代码语言:javascript
复制
plane.firstMaterial?.isDoubleSided = true

运行该应用程序以测试修复程序。因此,我们能够在检测到表面时将其可视化,在我的示例中是地板。但我们知道地板比那更大。不幸的是,当我四处走动时,网格并没有变大。

公式和图表

重构控制流程

在我们继续之前,我想重构if else语句。有一种更好的方式来编写它。我想从这种方式开始,使其更容易理解。另一种选择是使用guard语句。Guard是另一种类似于if else语句的控制流。它有助于避免开发中的错误,因为它会强制程序在失败的情况下退出。从这开始,我们将在整个课程中使用guard。

替换此代码块:

代码语言:javascript
复制
if anchor is ARPlaneAnchor {
} else {
    return
}

为这行代码:

代码语言:javascript
复制
guard anchor is ARPlaneAnchor else {return}

更新锚点

为了能够更新面锚点的大小,添加didUpdate后方法didAdd之一。

代码语言:javascript
复制
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {_

我们将采用与以前相同的想法。

代码语言:javascript
复制
guard anchor is ARPlaneAnchor else {return}
print("Horizontal surface updated")

运行应用程序。

与之前相同,我们将宣布一个planeAnchor

代码语言:javascript
复制
let planeAnchor = anchor as! ARPlaneAnchor

更新平面锚点的尺寸的方法,我们首先必须将其从场景中删除,然后将其添加回来。对于的所有子节点的节点,从父节点删除它们。

代码语言:javascript
复制
node.enumerateChildNodes { (childNode, _) in
    childNode.removeFromParentNode()
}

现在将其添加回场景,使用相同的功能创建另一个平面

代码语言:javascript
复制
let planeNode = createPlane(planeAnchor: planeAnchor)
node.addChildNode(planeNode)

再次运行该应用程序。您会看到在移动设备时,表面的大小会相应更新。

删除锚点

有时会发生错误。场景可以检测同一表面的多个锚点。我们可以通过添加didRemove方法来解决这个问题。

代码语言:javascript
复制
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {

然后,通过应用与之前相同的代码来删除平面锚点。

代码语言:javascript
复制
guard anchor is ARPlaneAnchor else {return}
print("Horizontal surface removed")
        
node.enumerateChildNodes { (childNode, _) in
childNode.removeFromParentNode()

结论

当我们上次预览我们导入的模型时,我们发现它只是漂浮在空中。检测平面锚点是允许我们添加模型,就像它们坐在它们上一样,使其成为更真实的体验。您在本教程中学到的内容不仅可以让您了解如何模拟真实曲面,还可以模拟现实生活中的事件。例如,您可以将物理应用于水平表面以使虚拟对象掉落,在其上驾驶汽车或在场景上为角色设置动画。

与此同时,我希望您能够在场景编辑器中学到的概念代码中受到教育。通过首先在视觉上向您介绍这些概念,我们相信它更容易掌握并且对代码处理不那么持怀疑态度。

原文: https://designcode.io/plane-detection

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.02.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 下载
  • 水平平面检测
  • ARSCNViewDelegate
  • 扩展课程
  • 导入套件
  • 延期
  • 添加锚点
  • 平面锚点
  • 平面节点
    • 平面几何
      • 飞机位置
        • 添加平面节点
          • 修复平面节点
          • 重构控制流程
          • 更新锚点
          • 删除锚点
          • 结论
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档