首页 文章

使用 ARAnchor 插入节点和直接插入节点之间有什么区别?

提问于
浏览
31

在 ARKit 中,我发现了 2 种在 hitTest 之后插入节点的方法

  • 插入 ARAnchor,然后在 renderer(_渲染器中创建节点:SCNSceneRenderer,nodeFor 锚点:ARAnchor)-> SCNNode?
let anchor = ARAnchor(transform:hit.worldTransform)
sceneView.session.add(anchor:anchor)
  • 直接插入节点
node.position = SCNVector3(hit.worldTransform.columns.3.x, hit.worldTransform.columns.3.y, hit.worldTransform.columns.3.z)
sceneView.scene.rootNode.addChildNode(node)

两者都希望为我工作,但是为什么要选择一种方法呢?

2 回答

  • 45

    **更新:**从 iOS 11.3(又名“ ARKit 1.5”)开始,在会话中添加ARAnchor(然后通过ARSCNViewDelegate回调将 SceneKit 内容与之关联)与仅将内容放置在 SceneKit 空间之间是有区别的。

    在会话中添加锚点时,您是在告诉 ARKit 世界空间中的某个点与您的应用有关。然后,ARKit 可以做一些额外的工作,以确保其世界协调的空间与现实世界准确地对齐,至少在该点附近。

    因此,如果您试图使虚拟内容看起来“附着”到某些 real-world 兴趣点上,例如将对象放在桌子或墙上,则由于 world-tracking 不准确,如果给该对象定锚,您应该会看到较少的“漂移”而不是将其放置在 SceneKit 空间中。而且,如果该对象从一个静态位置移动到另一个位置,则需要删除原始锚,然后在新位置添加一个。

    此外,在 iOS 11.3 中,您可以选择参加进行“重新本地化”,该过程可帮助 ARKit 在会话中断(通过电话,切换应用程序等)后恢复会话。在尝试弄清楚如何将以前的位置映射到现在的位置时,该会话仍然有效,一旦重新定位成功,这可能会导致定位符的 world-space 位置发生变化。

    (另一方面,如果您只是让漂浮在空中的太空入侵者,那么完美匹配的世界空间就没有那么重要了,因此您不会真正看到 anchor-based 和 non-anchor-based positioning.)之间的差异很大

    请参阅 Apple 的在增强现实中处理 3D 交互和 UI 控件文章/示例代码中的“使用锚点来提高虚拟对象周围的跟踪质量”一词。

    这个答案的其余部分在历史上仍然与 iOS 11.0-11.2.5 相关,并解释了一些上下文,因此我将其保留在下面...


    首先考虑不使用 SceneKit 的ARAnchor

    • 如果您使用的是ARSKView,则需要一种在 3D(real-world)空间中引用位置/方向的方法,因为 SpriteKit 不是 3D 的。您需要ARAnchor来跟踪 3D 中的位置,以便可以将它们映射到 2D 中。

    • 如果您要使用 Metal(或出于某些奇怪的原因而使用 GL)构建自己的引擎...这不是 3D 场景描述 API,而是 GPU 编程 API,因此它实际上没有世界空间的概念。您可以使用ARAnchor作为 ARKit 的世界空间概念与您构建的任何事物之间的桥梁。

    因此,在某些情况下,您需要ARAnchor,因为这是引用 3D 位置的唯一明智的方法。 (当然,如果您使用的是平面检测,则需要ARPlaneAnchor,因为 ARKit 会在优化对 are.)平面的估算时将其相对于场景空间移动


    使用ARSCNView时,SceneKit 已经具有 3D 世界坐标空间,ARKit 会完成使该空间与 ARKit 映射的 real-world 空间匹配的所有工作。因此,给定一个float4x4变换来描述世界空间中的位置(和方向等),您可以:

    • 创建一个ARAnchor,将其添加到会话中,然后响应ARSCNViewDelegate回调以为每个锚点提供 SceneKit 内容,ARKit 会将其添加到场景中并为您定位。

    • 创建一个SCNNode,设置其simdTransform,并将其添加为场景的rootNode的子级。

    只要您运行的是ARSession,这两种方法就没有区别-它们是表达同一件事的等效方法。因此,如果您喜欢使用 SceneKit 的方式进行操作,则没有任何问题。 (如果需要,您甚至可以使用SCNVector3SCNMatrix4而不是 SIMD 类型,但是如果还从 ARKit APIs.)获取 SIMD 类型,则必须来回转换。


    这些方法的不同之处是会话重置时。如果世界跟踪失败,您将恢复中断的会话,而 and/or 重新开始会话,则“世界空间”可能不再像在场景中放置内容时那样与现实世界对齐。

    在这种情况下,您可以让 ARKit 从会话中删除锚点-请参见run(_:options:)方法和ARSession.RunOptions。 (是的,它们全部,因为此时您不能相信它们中的任何一个都是有效的.anymore.)如果您使用锚点和委托回调将内容放置在场景中,ARKit 会核对所有内容。(您将得到的委托回调是是 removed.)如果您使用 SceneKit API 放置了内容,则它将保留在场景中(但很可能在错误的位置)。

    因此,使用哪种取决于您要如何处理会话失败和中断(除此之外,没有真正的区别)。

  • 0

    SCNVector3 只是“ three-component 向量的表示形式”。 SCNVector3 docs

    使用 ARAnchor 时,您可以访问 three-component 向量,但也可以“跟踪相对于摄像机的真实或虚拟对象的位置和方向” 锚文档。这就是为什么您使用会话来添加锚点而不是使用场景的原因。

    查看文档,您会发现 API :)的区别

    希望能帮助到你。

相关问题