在ARKit中,我发现了两种在命中测试后插入 node 的方法

  1. 插入一个ARAnchor,然后在renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?中创建 node

     let anchor = ARAnchor(transform:hit.worldTransform)
     sceneView.session.add(anchor:anchor)
    
  2. 直接插入 node

     node.position = SCNVector3(hit.worldTransform.columns.3.x, hit.worldTransform.columns.3.y, hit.worldTransform.columns.3.z)
     sceneView.scene.rootNode.addChildNode(node)
    

两人都希望为我工作,但为什么这样或那样?

推荐答案

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 记录,这两种方法之间就没有区别——它们是说同一件事的等效方法.所以,如果你喜欢用场景化的方式做事,那没什么错.(如果需要,您甚至可以使用SCNVector3SCNMatrix4代替SIMD类型,但如果您也从ARKit API获得SIMD类型,则必须来回转换.)


这些方法的不同之处在于会话重置时.如果世界跟踪失败,则恢复中断的会话,和/或

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

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

Swift相关问答推荐

自定义完整屏幕封面动画

我应该在自定义存储队列上使用弱self 吗?

在列表项内的NavigationLink中的按钮无法正常工作

SwiftUI—如何识别单词并获取视觉中的位置

SwiftData查询按日期排序的项的属性数组

从Firebase播放音频文件不起作用

从任务中打印

如何将新事例添加到枚举中?

如何在macOS中延迟退出应用程序的退出操作?

是否可以使用一个 NSRegularExpression 同时判断字符串格式并提取子字符串?

在 RealmSwift 中表示范围值?

覆盖一个子元素的 HStack 对齐方式

我如何遵守与演员的协议?

iOS SwiftUI - 无法转换 ObservedObject 类型的值

符合协议要求委托变量在 ios13 中可用

Swift 2.0 方法不能标记为@objc,因为参数的类型不能在 Objective-C 中表示

iOS 判断应用程序是否可以访问麦克风

'#selector' 的参数不引用 '@objc' 方法、属性或初始化程序

UITableViewCell 不显示 detailTextLabel.text - Swift

Swift中方法的弃用和其他属性,如何?