管理ARKit中对象相对于移动和旋转平面的移动

时间:2019-02-14 18:47:42

标签: swift 3d scenekit arkit trigonometry

我正在一个ARKit项目中,需要管理一个对象(白框)在平面(蓝色正方形)上的移动。

enter image description here

环境特征是:

  • 此框只能沿X和Z轴二维移动
  • 飞机可以从其3轴中心向3D旋转
  • 飞机可以在ARWorld中向各个方向移动。
  • 用户可以沿所有方向在平面上移动(显然,某些位置很难实现,但是随着平面可以移动,它也可以在用户上方或下方)。
  • 用户可以用手将设备绕设备的3轴(由设备的EulerAngles定义)旋转。

通过在设备上滑动来处理盒子的移动。无论用户或飞机处于什么位置,滑动操作都必须使滑动框相对于用户在屏幕上看到的方向沿滑动方向移动,而不必在框的坐标空间中使用相同的方向(向上滑动)例如,如果用户将用户向平面左侧移动了90°,或者在用户仍在原始位置的情况下,该平面向右旋转了90°,则设备可能位于该平面中如上图所示,将飞机指向用户前方。可能的组合是无限的。

我正在努力寻找解决方案。

我发现了一种解决方案,它可以通过EulerAngles属性给出的摄像头的俯仰,偏航和侧倾来管理用户围绕飞机的运动,如下所述。

func DefineARMovement(Level: LevelClass, NextMovement: inout eTypeMovement)
{
    let LevelNode = (MainPlayer.Level as! Level3DClass).TransformNode

        // Calculation of the angle of the camera taking into account the possible rotation of the plane. 
        // Works only if plane is rotating around Y axis.
    var CameraAngleBoardRef = SCNVector3.init(
        AngleDiff(AngleA: 90 - VCPlayAR.CameraAngles.x, AngleB: Float(RadiansToDegrees(Double(LevelNode.eulerAngles.x)).rounded(.up).RoundTo(Places: 0))),
        AngleDiff(AngleA: VCPlayAR.CameraAngles.y, AngleB: Float(RadiansToDegrees(Double(LevelNode.eulerAngles.y)).rounded(.up).RoundTo(Places: 0))),
        AngleDiff(AngleA: VCPlayAR.CameraAngles.z, AngleB: Float(RadiansToDegrees(Double(LevelNode.eulerAngles.z)).rounded(.up).RoundTo(Places: 0))))

    switch CameraAngleBoardRef.y
    {
    case _ where CameraAngleBoardRef.y > 315 || CameraAngleBoardRef.y < 45:
        break

    case _ where CameraAngleBoardRef.y > 45 && CameraAngleBoardRef.y < 135:
        switch NextMovement
        {
        case .Up:
            NextMovement = .Left

        case .Down:
            NextMovement = .Right

        case .Right:
            NextMovement = .Up

        case .Left:
            NextMovement = .Down

        default:
            break
      }

    case _ where CameraAngleBoardRef.y > 135 && CameraAngleBoardRef.y < 225:
        NextMovement = NextMovement.Inverse()

    case _ where CameraAngleBoardRef.y > 225 && CameraAngleBoardRef.y < 315:
        switch NextMovement
        {
        case .Up:
            NextMovement = .Right

        case .Down:
            NextMovement = .Left

        case .Right:
            NextMovement = .Down

        case .Left:
            NextMovement = .Up

        default:
            break
        }

    default:
        break
    }

    if CameraAngleBoardRef.x > 180 { NextMovement = NextMovement.Inverse() }
    if CameraAngleBoardRef.z > 180 { NextMovement = NextMovement.Inverse() }
}

但是一旦我开始以3D旋转平面,我就迷路了...

直觉上,我会说我需要:

  • 使用平面的节点的convertPosition属性轻松确定ARCamera在平面节点的坐标空间中的位置
  • 还要在平面节点的坐标空间中确定ARCamera的新EulerAngles,并考虑到ARWorld中ARCamera的初始EulerAngles
  • 使用新的EulerAngles模拟ARCamera在虚拟球体(上图中以平面中心为球体中心的虚拟球体)上的位置
  • 为球体的每个区域和ARCamera新EulerAngles的范围定义一套规则,这些规则会将设备上的滑动运动转换为立方体的实际运动

我的问题是,我不知道如何确定平面节点坐标空间中ARCamera的EulerAngles。

我也不知道如何在这里使用相机的Orientation或Rotation属性,因为ARCamera仅提供了Transform和EulerAngles属性(而且我不知道如何提取方向和/或旋转度)这些属性中的...)

如果有人考虑使用更简单的解决方案或已经存在的算法,我也很感兴趣

0 个答案:

没有答案