1
votes

ARKit 2.0 has AR data persistence using World Map. I want to achieve the same for below versions. Here's my approach: placing SCNNode after detecting vertical plane and adding to it local array.

Using FireBase Realtime DB to store ARAnchor with unique anchor ID. Next I'm retrieving ARAnchor from DB on tap of reload button. Find node corresponding to anchor with unique ID and adding it as child of scene root node. But this doesn't work as expected like ARKit 2.0. Node doesn't place at exact location it was last. Below is my code:

guard let node = self.selectedNode else { return }
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: node.anchor!, requiringSecureCoding: false) else { print("Could not archeive" )
   return 
}

let string = data.base64EncodedString()
self.saveData(dataString: string, forKey: node.name!)

func saveData(dataString : String, forKey : String)  {
    db.collection("roomdecorateDB").document(forKey).setData([
        "anchor": dataString]) { err in
        if let err = err {
            print("Error writing document: \(err)")
        } else {
            print("Document successfully written!")
        }
    }
}

func reloadData() { 
    guard let cloudAnchor = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ARAnchor.self, from: data) else { return print("Could not decode") }
    print("world map \(cloudAnchor!)")
    // Run the session with the received world map.
    let configuration = self.standardConfiguration
    self.sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    self.sceneView.session.add(anchor: cloudAnchor!)
    // document id is the name of node, we can find node from node array and place to scene view
    guard  let node = self.nodeArray.first(where: {$0.name == document.documentID})else {continue}
    node.position = SCNVector3((cloudAnchor?.transform.columns.3.x)!, (cloudAnchor?.transform.columns.3.y)!, (cloudAnchor?.transform.columns.3.z)!)
    self.sceneView.scene.rootNode.addChildNode(node)
}

Any help would be really appreaciated.

1

1 Answers

0
votes

It's not a good idea. There's no access to World Map Data for developers in ARKit 1.0 and ARKit 1.5 via Apple tools. The Persistence as well as Multiuser AR Experience options are available only in ARKit 2.0 for iOS 12.

ARKit 2.0 contains all necessary classes, methods and instance properties for saving and retrieving precise World Map Data. It's supported not only by apps in iOS 12 but the Operating System itself.

Does it make sense to develop for iOS11? Here's a list of devices supporting iOS12 (ARKit cuts compatibility to iPhones 6s and higher and iPad 2017 and higher):

enter image description here

Apple Developer Documentation about ARWorldMap class.

Saving an ARWorldMap to a file URL in iOS12 is as simple as that:

func writeWorldMap(_ worldMap: ARWorldMap, to url: URL) throws {
    let data = try NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true)
    try data.write(to: url)
}

Loading an ARWorldMap from a file URL is as simple as that:

func loadWorldMap(from url: URL) throws -> ARWorldMap {
    let mapData = try Data(contentsOf: url)
    guard let worldMap = try NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, from: mapData)
        else { throw ARError(.invalidWorldMap) }
    return worldMap
}