在 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 回答
**更新:**从 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 的方式进行操作,则没有任何问题。 (如果需要,您甚至可以使用SCNVector3
和SCNMatrix4
而不是 SIMD 类型,但是如果还从 ARKit APIs.)获取 SIMD 类型,则必须来回转换。这些方法的不同之处是会话重置时。如果世界跟踪失败,您将恢复中断的会话,而 and/or 重新开始会话,则“世界空间”可能不再像在场景中放置内容时那样与现实世界对齐。
在这种情况下,您可以让 ARKit 从会话中删除锚点-请参见run(_:options:)方法和ARSession.RunOptions。 (是的,它们全部,因为此时您不能相信它们中的任何一个都是有效的.anymore.)如果您使用锚点和委托回调将内容放置在场景中,ARKit 会核对所有内容。(您将得到的委托回调是是 removed.)如果您使用 SceneKit API 放置了内容,则它将保留在场景中(但很可能在错误的位置)。
因此,使用哪种取决于您要如何处理会话失败和中断(除此之外,没有真正的区别)。
SCNVector3 只是“ three-component 向量的表示形式”。 SCNVector3 docs。
使用 ARAnchor 时,您可以访问 three-component 向量,但也可以“跟踪相对于摄像机的真实或虚拟对象的位置和方向” 锚文档。这就是为什么您使用会话来添加锚点而不是使用场景的原因。
查看文档,您会发现 API :)的区别
希望能帮助到你。