我正在使用 ARKit 构建一个简单的导航应用程序。该应用程序会在目的地(可能很远或附近)上显示图钉。用户能够走向图钉进行导航。

在我的ARSCNView中,我有一个名为waypointNodeSCNNode,它表示目标位置的引脚。

为了确定waypointNode的放置位置,我以米为单位计算了distance到目的地的距离,并计算了bearing(与北方的距离)。然后,我创建并乘以一些转换并将其应用于节点以将其放置在适当的位置。

还有一些逻辑可以确定waypointNode的最大距离,因此对于用户来说,它的距离不能太小。

这就是我配置ARSCNView的方式,因此轴与 real-world 罗盘方向对齐:

func setUpSceneView() {
    let configuration = ARWorldTrackingConfiguration()
    configuration.worldAlignment = .gravityAndHeading
    configuration.planeDetection = .horizontal
    session.run(configuration, options: [.resetTracking])
}

每次设备从 CoreLocation 获取新的 CLLocation 时,我都会更新distancebearing,然后调用此函数来更新waypointNode的位置:

func updateWaypointNode() {

    // limit the max distance so the node doesn't become invisible
    let distanceLimit: Float = 80

    let translationDistance: Float
    if navigationInfo.distance > distanceLimit {
        translationDistance = distanceLimit
    } else {
        translationDistance = navigationInfo.distance
    }

    // transform matrix to adjust node distance
    let distanceTranslation = SCNMatrix4MakeTranslation(0, 0, -translationDistance)

    // transform matrix to rotate node around y-axis
    let rotation = SCNMatrix4MakeRotation(-1 * GLKMathDegreesToRadians(Float(navigationInfo.bearing)), 0, 1, 0)

    // multiply the rotation and distance translation matrices
    let distanceTimesRotation = SCNMatrix4Mult(distanceTranslation, rotation)

    // grab the current camera transform
    guard let cameraTransform = session.currentFrame?.camera.transform else { return }

    // multiply the rotation and distance translation transform by the camera transform
    let finalTransform = SCNMatrix4Mult(SCNMatrix4(cameraTransform), distanceTimesRotation)

    // update the waypoint node with this updated transform
    waypointNode.transform = finalTransform
}

当用户第一次开始会话时,以及当用户移动不到 100m 时,这种方法都可以正常工作。

一旦用户覆盖相当长的距离,例如超过 100m 的步行或驾车,仅呼叫updateWaypointNode()就不足以维持节点在目的地的正确位置。例如,当走向节点时,即使用户尚未到达目的地,用户也有可能最终到达该节点。注意:这种不正确的定位发生在会话始终打开的过程中,而不是如果会话被中断。

作为一种解决方法,每次设备更新位置信息时,我也会拨打 setUpSceneView().

即使这样可以正常工作,但对我来说还是错的。似乎我不必每次都用.resetTracking选项调用run。我想我可能只是忽略了翻译中的某些内容。我还看到,每次在运行会话时调用run时,照相机中都会出现一些跳跃现象,因此,这比简单地更新翻译要少。

是否有其他方法可以避免在设备每次获取位置更新时避免调用会话运行并重置跟踪?