在ARKit ARWorldMap中保持对象方向

时间:2018-11-20 21:09:41

标签: ios swift scenekit arkit arworldmap

我正在尝试使用ARWorldMap将模型持久化在ARKit中。我可以保存和加载模型,但是在保存之前应用于对象的方向不会与对象保持一致。

我目前正在做什么

对象已保存并加载:

  /// - Tag: GetWorldMap
  @objc func saveExperience(_ button: UIButton) {
    sceneView.session.getCurrentWorldMap { worldMap, error in
      guard let map = worldMap
        else { self.showAlert(title: "Can't get current world map", message: error!.localizedDescription); return }

      // Add a snapshot image indicating where the map was captured.
      guard let snapshotAnchor = SnapshotAnchor(capturing: self.sceneView) else {
        fatalError("Can't take snapshot")

      }
      map.anchors.append(snapshotAnchor)

      do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: map, requiringSecureCoding: true)
        try data.write(to: self.mapSaveURL, options: [.atomic])
        DispatchQueue.main.async {
          self.loadExperienceButton.isHidden = false
          self.loadExperienceButton.isEnabled = true
        }
      } catch {
        fatalError("Can't save map: \(error.localizedDescription)")
      }
    }
  }

  /// - Tag: RunWithWorldMap
  @objc func loadExperience(_ button: UIButton) {

    /// - Tag: ReadWorldMap
    let worldMap: ARWorldMap = {
      guard let data = mapDataFromFile
        else { fatalError("Map data should already be verified to exist before Load button is enabled.") }
      do {
        guard let worldMap = try NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, from: data)
          else { fatalError("No ARWorldMap in archive.") }
        return worldMap
      } catch {
        fatalError("Can't unarchive ARWorldMap from file data: \(error)")
      }
    }()

    // Display the snapshot image stored in the world map to aid user in relocalizing.
    if let snapshotData = worldMap.snapshotAnchor?.imageData,
      let snapshot = UIImage(data: snapshotData) {
      self.snapshotThumbnail.image = snapshot
    } else {
      print("No snapshot image in world map")
    }
    // Remove the snapshot anchor from the world map since we do not need it in the scene.
    worldMap.anchors.removeAll(where: { $0 is SnapshotAnchor })

    let configuration = self.defaultConfiguration // this app's standard world tracking settings
    configuration.initialWorldMap = worldMap
    sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])

    isRelocalizingMap = true
    virtualObjectAnchor = nil
  }

旋转:

@objc func didRotate(_ gesture: UIRotationGestureRecognizer) {
    sceneView.scene.rootNode.eulerAngles.y = objectRotation
    gesture.rotation = 0
}

然后将其呈现:

  func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard anchor.name == virtualObjectAnchorName else {
      return
    }

    // save the reference to the virtual object anchor when the anchor is added from relocalizing
    if virtualObjectAnchor == nil {
      virtualObjectAnchor = anchor
    }
    node.addChildNode(virtualObject)
  }

我该怎么做?

我该怎么做?我尝试了多种解决方案,但是方向从未保持。它将对象加载到正确的位置,但是即使我将其应用于根节点,也永远不会保持旋转和缩放。我可以看到的唯一选择是将转换也存储为单独的数据对象,然后加载并应用它。但是似乎应该可以将数据与对象一起存储。

1 个答案:

答案 0 :(得分:2)

Apple Documentation for ARWorldMap显示ARWorldMap类的属性为: <code>anchors: [ARAnchor]</code>, <code>center: simd_float3</code>, and <code>extent: simd_float3</code>

存档世界地图时,这些是唯一保存的信息。在存档期间,有关会话期间添加到锚点的节点的任何信息(例如,更改节点的比例和方向)都不会与世界地图一起保存。

我记得在一次WWDC会议上,他们演示了一款名为SwiftShot的多人AR游戏,其中玩家用球击中了不同的物体。他们提供了源代码,我注意到他们使用了一个名为ARAnchor的自定义BoardAnchor子类,该子类用于在锚定类中存储其他信息,例如游戏板的大小。 参见:SwiftShot: Creating a Game for Augmented Reality

您可以使用相同的方法来存储节点的比例和方向,例如,这样当您取消存档世界地图并将其重新定位时,可以使用ARSCNViewDelegate的{​​{1} },以根据自定义renderer(_:didAdd:for:)中存储的信息来调整节点的大小和缩放比例。