如何确定ARKit检测到的表面是否不再可用?

我正在使用ARKit和SceneKit框架开发应用程序 . 在我的应用程序中,我启用了表面检测(我按照Apple提供的放置对象样本) . 如何查找检测到的表面是否不再可用?也就是说,最初只有当用户在ARSession中检测到表面时,我才允许他放置3D对象 .

但是如果用户快速移动或聚焦某处,则检测到的表面区域会丢失 . 在这种情况下,如果用户试图放置另一个物体,我不应该让它放置,直到他再次扫描地板并修正表面 .

是否有任何代表可以告诉我们检测到的表面不再可用?

回答(2)

2 years ago

您可以使用委托功能 . 代表是 ARSCNViewDelegate

它有一个 renderer(_:didRemove:for:) 函数,当ARAnchor被移除时会触发它 . 当表面被移除时,您可以使用此功能执行某些操作 .

ARSCNViewDelegate Link

2 years ago

有两种方法可以“丢失”一个表面,因此处理这样一个问题的方法不止一种 .


如另一个答案中所述,当从AR会话中删除锚点时,ARKit会调用 ARSCNViewDelegate 方法 . 但是,ARKit在运行会话期间不会删除平面锚点 - 一旦检测到平面,它就会假定平面始终存在 . 因此只有在以下情况下调用该方法:

  • 您可以通过将平面锚点传递给 session.remove(anchor:) 来直接删除它

  • 通过使用 .removeExistingAnchors 选项再次运行会话来重置会话 .

我不确定前者是个好主意,但后者很重要,所以你可能希望你的代表能够很好地处理它 .


你也可以通过让它离开视图来“丢失”一个表面 - 例如,ARKit检测到一个表,然后用户转过身,这样相机就不再指向或靠近 table 了 .

ARKit本身不会为您解决此问题提供任何帮助 . 但是,它为您提供了自己进行数学运算所需的所有信息 . 您可以获得飞机锚的位置,方向和大小,以便计算其四个角点 . 你得到了相机的投影矩阵,所以你可以check for whether any point is in the viewing frustum .

既然你已经在使用SceneKit,那么还有一些方法可以让SceneKit为你做数学运算......向后工作:

  • SceneKit为您提供isNode(_:insideFrustumOf:)测试,因此如果您的边界框与您的平面锚点的范围匹配 SCNNode ,您可以将其与相机( view.pointOfView )一起传递以查明该节点是否可见 .

  • 要获取边界框与平面锚点匹配的节点,请实现 ARSCNViewDelegate didAdddidUpdate 回调以创建/更新 SCNPlane ,其位置和尺寸与 ARPlaneAnchor 的中心和范围相匹配 . (不要忘记侧面翻转平面,因为 SCNPlane 默认是垂直方向 . )

  • 如果您不希望在AR视图中看到该平面,请将其材质设置为透明 .