了解 ARKit 中的坐标空间

Understand coordinate spaces in ARKit

我已阅读所有有关 ARKit, and watched a WWDC video 的 Apple 指南。但我无法理解绑定到的坐标系如何:

  1. 真实世界
  2. 一台设备
  3. 3D 场景

相互联系。

我可以添加一个对象,例如 SCNPlane:

let stripe = SCNPlane(width: 0.005, height: 0.1)
let stripeNode = SCNNode(geometry: stripe)
scene.rootNode.addChildNode(stripeNode)

这将产生一条白色条纹,无论此时设备的朝向如何,该条纹都将垂直放置。这意味着坐标系以某种方式受重力约束!但是,如果我尝试每帧打印 upAxis attribute of the SCNScene,无论我如何旋转 iPhone,结果都是一样的。我也尝试打印 stripeNode.worldTransform 并且它也没有改变。

欢迎在理解 ARKit 坐标方面提供任何帮助。

默认情况下,ARKit 中的世界坐标系基于 ARKit 对您设备周围真实世界的理解。 (是的,它是 oriented to gravity,多亏了设备的运动感应硬件。)

同样默认情况下,当您使用 ARSCNView 在 ARKit 会话中显示 SceneKit 内容时,场景的 rootNode 坐标系与 ARKit 世界坐标系相匹配。这意味着无论您如何移动设备,场景 space 中的“向上”始终与现实世界中的“向上”相同 space。

Aside: The scene attributes API where you found an upAxis aren't what you think they are. Those are for the inherent settings of scenes loaded from files — e.g. someone sends you a DAE file designed in a 3D authoring tool where the Z axis means "up", so that attribute tells SceneKit to rotate the data in that file to fit SceneKit's Y-up coordinate system convention.

If you want to find the up axis of some SceneKit node relative to world space, the worldUp or simdWorldUp property is what you want. However, those are relative to world space. There's no API for asking what direction world space itself points in, because that would mean a direction relative to something else... and world space is the "absolute" coordinate system that everything else is relative to. So you have to rely on definition.

这种坐标系匹配的好处在于,您可以非常轻松地将 SceneKit 的东西放在现实世界中 space。您的代码在 0, 0, 0 处放置了一条白色条纹,因为您没有明确给它一个位置。在 ARKit 会话中,0, 0, 0 是您开始会话时设备的位置...因此您应该能够 运行 该代码,然后向后退一步以查看您的 white stripe.


简而言之,ARKit的坐标系模型是这样的:世界是固定的,而你的device/camera在其中移动。

这意味着如果你想做任何与设备当前position/orientation相关的事情,你需要转换为相机space。

如果您使用的是 SceneKit,那很简单:view.pointOfView 为您提供了 SceneKit 相机节点,因此您可以...

  • 向该节点添加子节点,它们将在您移动相机时保持“附加”到相机(例如,HUD 元素,或者如果您正在制作类似 Minecraft 的东西,则可能是镐)
  • 使用摄像机节点作为 constraint 的目标,使场景中的其他内容在您移动摄像机时与摄像机交互(例如,让游戏角色注视摄像机)
  • 使用摄像机节点的变换(或访问部分变换的各种便利属性)来定位场景中的其他内容(例如 node.position = view.pointOfView.simdWorldFront + float3(0, 0, -0.5) 将节点放在摄像机所在位置前方 50 厘米处现在)