Update:截至iOS 11.3(又名"ARKit 1.5"),在会话中添加ARAnchor
(然后通过ARSCNViewDelegate
次回调将SceneKit内容与之关联)和仅将内容放置在SceneKit空间之间存在差异.
当你向会话添加锚定时,你在告诉ARKit世界空间中的某个点与你的应用程序相关.然后,ARKit可以做一些额外的工作,以确保其世界坐标空间与真实世界精确对齐,至少在该点附近.
所以,如果你想让虚拟内容看起来"依附"在现实世界中的某个兴趣点上,比如把一个物体放在桌子或墙上,那么如果你给这个物体一个锚定,而不是仅仅把它放在场景空间中,你应该会看到较少的"漂移",因为世界跟踪不准确.如果该对象从一个静态位置移动到另一个静态位置,则需要移除原始锚点,然后在新位置添加一个锚点.
此外,在iOS 11.3中,你可以 Select "重新定位",这是一个帮助ARKit在会话被中断(通过电话、切换应用程序等)后恢复会话的过程.该课程在试图找出如何将以前的位置映射到现在的位置时仍然有效,这可能会导致重新定位成功后锚的世界空间位置发生变化.
(另一方面,如果你只是制造漂浮在空中的太空入侵者,完美匹配世界空间就不那么重要了,因此你不会真正看到锚定定位和非锚定定位之间有多大区别.)
请参阅Apple的Handling 3D Interaction and UI Controls in Augmented Reality篇文章/示例代码中关于"使用锚来提高虚拟对象的跟踪质量"的部分.
The rest of this answer remains historically relevant to iOS 11.0-11.2.5 and explains some context, so I'll leave it below...
首先考虑使用ARAnchor
without ScEnKIT.
如果你使用ARSKView
,你需要一种在3D(真实世界)空间中参考位置/方向的方法,因为SpriteKit不是3D的.你需要ARAnchor
来跟踪3D中的位置,这样它们就可以被映射到2D中.
如果你正在用金属(或GL,出于某种奇怪的原因)制造自己的发动机...这不是一个3D场景描述API,而是一个GPU编程API,所以它没有真正的世界空间概念.你可以用ARAnchor
作为ARKit的世界空间概念和你建造的任何东西之间的桥梁.
所以在某些情况下,你需要ARAnchor
,因为这是指3D位置的唯一合理方式.(当然,如果你使用的是平面检测,你需要ARPlaneAnchor
,因为当它精确估计平面位置时,它实际上会相对于场景空间移动这些平面.)
SceneKit已经有了一个3D世界坐标空间,ARKit做了所有工作,使该空间与ARKit绘制的真实世界空间相匹配.因此,给定一个描述世界空间中位置(和方向等)的float4x4
变换,您可以:
- 创建一个
ARAnchor
,将其添加到会话中,并响应ARSCNViewDelegate
回调, for each 锚提供SceneKit内容,ARKit将为您添加并在场景中定位这些内容.
- 创建一个
SCNNode
,设置其simdTransform
,并将其添加为场景rootNode
的子对象.
只要你有一个ARSession
人的 run 记录,这两种方法之间就没有区别——它们是说同一件事的等效方法.所以,如果你喜欢用场景化的方式做事,那没什么错.(如果需要,您甚至可以使用SCNVector3
和SCNMatrix4
代替SIMD类型,但如果您也从ARKit API获得SIMD类型,则必须来回转换.)
这些方法的不同之处在于会话重置时.如果世界跟踪失败,则恢复中断的会话,和/或
在这种情况下,您可以让ARKit从会话中移除锚——请参阅run(_:options:)
方法和ARSession.RunOptions
.(是的,所有这些,因为在这一点上,你不能再相信它们中的任何一个是有效的.)如果使用锚定和代理回调将内容放置在场景中,ARKit将取消所有内容.(您将收到正在删除的代理回调.)如果使用SceneKit API放置内容,它会留在场景中(但很可能放错了位置).
所以,使用哪一种取决于您希望如何处理会话失败和中断(除此之外,没有真正的区别).