使用 ARAnchor 插入节点和直接插入节点有啥区别?

Posted

技术标签:

【中文标题】使用 ARAnchor 插入节点和直接插入节点有啥区别?【英文标题】:What's the difference between using ARAnchor to insert a node and directly insert a node?使用 ARAnchor 插入节点和直接插入节点有什么区别? 【发布时间】:2017-12-22 15:34:01 【问题描述】:

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

    插入一个 ARAnchor 然后在 renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: 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)
    

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

【问题讨论】:

【参考方案1】:

更新:ios 11.3(又名“ARKit 1.5”)开始,在会话中添加 ARAnchor(然后关联 SceneKit 内容)之间存在区别通过ARSCNViewDelegate 回调)并在 SceneKit 空间中放置内容。

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

因此,如果您试图让虚拟内容看起来“附加”到某个现实世界的兴趣点,例如将对象放在桌子或墙上,由于世界跟踪不准确,您应该会看到更少的“漂移”如果你给那个对象一个锚点,而不是把它放在 SceneKit 空间中。如果该对象从一个静态位置移动到另一个静态位置,您需要移除原始锚点,然后在新位置添加一个。

此外,在 iOS 11.3 中,您可以 opt in 进行“重新定位”,这是一个帮助 ARKit 在会话被中断(通过电话、切换应用程序等)后恢复会话的过程。该会话在尝试找出如何将您之前的位置映射到您现在的位置时仍然有效,这可能会导致重新定位成功后锚点的世界空间位置发生变化。

(另一方面,如果您只是制作漂浮在空中的太空入侵者,那么完美匹配的世界空间并不那么重要,因此您不会真正看到基于锚点和非基于锚点的空间有太大区别。基于锚的定位。)

请参阅 Apple 的 Handling 3D Interaction and UI Controls in Augmented Reality 文章/示例代码中有关“使用锚点提高虚拟对象周围的跟踪质量”的内容。

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


首先考虑使用ARAnchor 没有 SceneKit。

如果您使用ARSKView,您需要一种方法来参考 3D(真实世界)空间中的位置/方向,因为 SpriteKit 不是 3D。您需要ARAnchor 来跟踪 3D 中的位置,以便将它们映射到 2D。

如果您使用 Metal(或 GL,出于某种奇怪的原因)构建自己的引擎……那不是 3D 场景描述 API — 它是 GPU 编程 API — 所以它实际上没有世界空间的概念。您可以使用ARAnchor 作为 ARKit 的世界空间概念与您构建的任何东西之间的桥梁。

所以在某些情况下,您需要ARAnchor,因为这是引用 3D 位置的唯一合理方式。 (当然,如果您使用平面检测,则需要 ARPlaneAnchor,因为 ARKit 实际上会在改进对平面位置的估计时相对于场景空间移动这些。)


有了ARSCNView,SceneKit 已经有了一个 3D 世界坐标空间,而 ARKit 会做所有的工作来使这个空间与 ARKit 映射的真实世界空间相匹配。因此,给定一个描述世界空间中位置(和方向等)的float4x4 变换,您可以:

创建一个ARAnchor,将其添加到会话中,并响应ARSCNViewDelegate 回调,为每个锚点提供SceneKit 内容,ARKit 将为您添加并定位到场景中。 创建一个SCNNode,设置它的simdTransform,并将其添加为场景rootNode 的子元素。

只要您有一个正在运行的ARSession,这两种方法之间就没有区别——它们是相同的表达方式。所以如果你喜欢用 SceneKit 的方式做事,那没有什么问题。 (如果需要,您甚至可以使用 SCNVector3SCNMatrix4 代替 SIMD 类型,但如果您还从 ARKit API 获取 SIMD 类型,则必须来回转换。)


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

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

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

【讨论】:

所以原因:1)ARNode适用于非SceneKit引擎(SpriteKit、Metal等),对于SceneKit也是一样的(因为ARKit是从SceneKit派生的,具有相同的世界坐标), 2) 如果跟踪失败,ARKit 可以自动删除所有 ARAnchor(以及关联的节点),但 SceneKit 不会。对吗? @LimThyeChean 是的。 @rickster 感谢您的解释!这为我节省了很多时间。 我想我更困惑了。那么我们是否需要通过委托方法添加锚点和节点。或者如果我们只添加节点就可以了吗?什么是“正确的方式”,正确的方式?我觉得正确的方法是添加锚点然后添加节点。 添加锚点,然后使用委托回调在 ARKit 为您创建的节点下添加内容。【参考方案2】:

SCNVector3 只是“三分量向量的表示”。 SCNVector3 docs.

使用 ARAnchor 时,您可以访问三分量矢量,而且您还可以“跟踪真实或虚拟对象相对于相机的位置和方向”ARAnchor docs。这就是为什么您使用会话来添加锚点而不是使用场景的原因。

查看文档,您可以看到 API 方面的差异 :)

希望对你有帮助。

【讨论】:

这并不能解释使用带有transform 属性的SCNNode 和带有transform 属性的ARAnchor 之间的区别。 @orangenkopf 你是对的,两者都有效。事实上,Apple 似乎列出了这两种方式可以相互替代,但为什么我要为每个节点添加一个额外的 ARAnchor 呢?该节点似乎定位良好。苹果文档:developer.apple.com/documentation/arkit/arscnview/… 锚点在现实世界中有一个固定的位置。你不能移动锚。添加节点只是添加一些视觉效果,您可以稍后更改节点的位置。 API正在为例如添加锚点是有道理的。飞机,但我看不出你应该手动添加飞机的理由

以上是关于使用 ARAnchor 插入节点和直接插入节点有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

廖雪峰js教程笔记13 插入DOM

JavaScript--插入DOM

jQuery学习-属性访问,插入节点

js浏览器操作DOM之插入DOM

源码角度了解ConcurrentSkipListMap

HashMap插入节点详细过程