在ARKit中,我发现了2种在hitTest之后插入节点的方法
插入一个ARAnchor,然后在renderer中创建节点(_ 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)
两者都希望为我工作,但是为什么要选择一种方法呢?
更新: 从iOS 11.3(又名“ ARKit 1.5”)开始,将an添加到会话(然后通过回调将SceneKit内容与其关联)与仅将内容放入SceneKit空间之间 是 有区别的。ARAnchor``ARSCNViewDelegate
ARAnchor``ARSCNViewDelegate
在会话中添加锚点时,是在告诉ARKit世界空间中的某个点与您的应用有关。然后,ARKit可以做一些额外的工作,以确保其世界协调的空间与现实世界准确地对齐,至少在该点附近。
因此,如果您尝试使虚拟内容看起来“附着”在某些现实世界的兴趣点上(例如,将物体放在桌子或墙上),则由于世界跟踪的不准确性,您应该看到较少的“漂移”将该对象作为锚,而不是将其放置在SceneKit空间中。而且,如果该对象从一个静态位置移动到另一个位置,则需要删除原始锚,然后在新位置添加一个。
此外,在iOS 11.3中,您可以选择 “重新本地化”,该过程可帮助ARKit在会话中断(通过电话,切换应用程序等)后恢复会话。该会话仍在尝试找出如何将以前的位置映射到现在的位置时仍然有效,这可能会导致重新定位成功后锚的世界空间位置发生变化。
(另一方面,如果您只是让漂浮在空中的入侵者,那么完全匹配的世界空间就没有那么重要了,因此,基于锚和基于非锚的差异不会太大定位。)
请参阅“ 增强现实”文章/示例代码中“ 处理3D交互和UI控件 ”中“使用锚来改善虚拟对象周围的跟踪质量”中的内容。
这个答案的其余部分在历史上仍然与iOS 11.0-11.2.5相关,并解释了一些上下文,因此我将其保留在下面…
首先考虑ARAnchor 不 使用SceneKit 的 情况 。
ARAnchor
如果使用ARSKView,则需要一种在3D(真实世界)空间中引用位置/方向的方法,因为SpriteKit不是3D。您需要ARAnchor跟踪3D中的位置,以便可以将它们映射到2D中。
ARSKView
如果您要使用Metal(或出于某些奇怪的原因而使用GL)构建自己的引擎…这不是3D场景描述API,而是GPU编程API,因此它实际上没有世界空间的概念。您可以ARAnchor用作ARKit的世界空间概念与所构建内容之间的桥梁。
因此在某些情况下您需要,ARAnchor因为这是引用3D位置的唯一明智的方法。(当然,如果您使用的是平面检测,则需ARPlaneAnchor要这样做,因为ARKit会在优化平面位置的估计时将它们相对于场景空间移动。)
ARPlaneAnchor
有了ARSCNView,SceneKit已经具有3D世界坐标空间,ARKit会完成使该空间与ARKit映射的真实空间匹配的所有工作。因此,给定一个float4x4描述世界空间中位置(和方位等)的变换,您可以:
ARSCNView
float4x4
ARSCNViewDelegate
SCNNode
simdTransform
rootNode
只要您跑步ARSession,这两种方法就没有区别- 它们是表达同一件事的等效方法。因此,如果您喜欢使用SceneKit的方式进行操作,则没有任何问题。(如果需要,甚至可以使用SCNVector3而SCNMatrix4不是SIMD类型,但是如果还从ARKit API获取SIMD类型,则必须来回转换。)
ARSession
SCNVector3
SCNMatrix4
这些方法的不同之处是会话重置时。如果世界跟踪失败,您将恢复中断的会话,和/或重新开始会话,则“世界空间”可能不再像在场景中放置内容时那样与现实世界对齐。
在这种情况下,您可以让ARKit从会话中删除锚点- 请参见和run(_:options:)方法ARSession.RunOptions。(是的,所有这些,因为此时您不能再信任它们中的任何一个了。)如果您使用锚点和委托回调将内容放置在场景中,则ARKit会核对所有内容。(您将获得被删除的委托回调。)如果使用SceneKit API放置了内容,则内容将保留在场景中(但很可能在错误的位置)。
run(_:options:)
ARSession.RunOptions
因此,使用哪种取决于您要如何处理会话失败和中断(除此之外,没有真正的区别)。