使用ARAnchor插入节点并直接插入节点有什么区别?

Lim*_*ean 32 augmented-reality swift arkit

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

  1. 插入ARAnchor然后在渲染器中创建节点(_ renderer:SCNSceneRenderer,nodeFor anchor:ARAnchor) - > SCNNode?

    let anchor = ARAnchor(transform:hit.worldTransform)
    sceneView.session.add(anchor:anchor)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 直接插入节点

    node.position = SCNVector3(hit.worldTransform.columns.3.x, hit.worldTransform.columns.3.y, hit.worldTransform.columns.3.z)
    sceneView.scene.rootNode.addChildNode(node)
    
    Run Code Online (Sandbox Code Playgroud)

两者都看起来适合我,但为什么这样或那样?

ric*_*ter 48

更新:作为在IOS 11.3的(又名"ARKit 1.5"),有加入之间的差ARAnchor给会话(然后SceneKit内容与它相关联的通过ARSCNViewDelegate回调),只是将在SceneKit空间内容.

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

所以,如果你试图让虚拟内容"附加"到一些真实世界的兴趣点,比如把一个物体放在桌子或墙上,你应该看到由于世界跟踪的不准确而导致的"漂移"减少该对象是一个锚,而不是只是将它放在SceneKit空间中.如果该对象从一个静态位置移动到另一个静态位置,您将需要删除原始锚点,然后在新位置添加一个.

此外,在iOS 11.3中,您可以选择 "重定位",这是一个帮助ARKit在被中断(通过电话,切换应用程序等)后恢复会话的过程.会议仍然有效,同时它正试图弄清楚如何将你以前的位置映射到现在的位置,这可能会导致锚点的世界空间位置在重新定位成功后发生变化.

(另一方面,如果你只是让空间入侵者漂浮在空中,完美匹配的世界空间并不那么重要,因此你不会真正看到基于锚点和非锚点之间的差异很大定位.)

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

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


首先考虑使用ARAnchor 没有 SceneKit.

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

  • 如果您正在使用Metal(或GL,出于某种奇怪的原因)构建自己的引擎......那不是3D场景描述API - 它是一个GPU编程API - 所以它实际上没有世界空间的概念.您可以将ARAnchorARKit的世界空间概念与您构建的任何东西联系起来.

所以在某些情况下你需要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放置内容,它会留在场景中(但很可能在错误的地方).

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