如何在SwiftUI应用中保存和加载ARWorldMap? [英] How do I save and load ARWorldMap in SwiftUI app?

查看:161
本文介绍了如何在SwiftUI应用中保存和加载ARWorldMap?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循了YouTube教程,内容涉及如何在SwiftUI中放置虚拟模型.

I followed a YouTube tutorial on how to place virtual Models in SwiftUI.

现在我可以放置模型了,我想保存和加载模型位置.

Now that I can place my Models, I would like to save and load the models position.

我已经制作了2个用于保存和加载的按钮,但是我不知道正确的代码来保存和加载实体和锚点.

I have already made 2 Buttons for save and load, but I don't know the correct code to save and load the Entities and Anchors.

以下代码位于我的updateUIView函数内部:

The following code is inside my updateUIView function:

func updateUIView(_ uiView: ARView, context: Context) {

    if let name = self.modelName {
              
        print("Modell mit dem Namen \(name) wurde zum plaziert")
                  
         let filename = name + ".usdz"
         let modelEntity = try! ModelEntity.loadModel(named: filename)
              
         modelEntity.generateCollisionShapes(recursive: true)
         uiView.installGestures(.all, for: modelEntity)                  
              
         let anchorEntity = AnchorEntity(plane: .any)
         anchorEntity.addChild(modelEntity)
              
         uiView.scene.addAnchor(anchorEntity)            
    }
}

我尝试了"else"语句,因为我有"if"语句.在一开始的时候.但这并没有解决.我创建了一个状态变量(布尔型),当我按下保存"或加载"按钮时会触发该状态变量.但是我无法正确连接到updateUIView功能.

I tried it with an "else"-statement, since I had the "if" in the beginning. But this did not work out. I made a state variable (type Boolean), which triggers when I press the save or load button. but I can't get the connection to the updateUIView-function right.

我在"updateUIView"内部实现了保存和加载功能.这样的功能:

I implemented the save and load functions inside my "updateUIView" function like this:

struct ARViewContainer: UIViewRepresentable {
    
    @Binding var reset: Bool
    @Binding var modelSelector: String
    @Binding var save: Bool
    @Binding var load: Bool

    let config = ARWorldTrackingConfiguration()


    
    
    
    
    func makeUIView(context: Context) -> ARView {
        
        
        
        // create config for all entities
        
        
         let arView = ARView(frame: .zero)


            config.planeDetection = [.horizontal, .vertical]
            config.environmentTexturing = .automatic
            config.sceneReconstruction = .mesh
        
        
        
        arView.session.run(config)
        
        
        
        return arView
        
    }
    

    
    
    // App kontinuierlich beobachten
    func updateUIView(_ uiView: ARView, context: Context) {
        
        
        // create anchor and model-Entity
        if modelSelector != "default" {
            
            let modelEntity = try! ModelEntity.loadModel(named: "\(modelSelector)")
            modelEntity.name = ("\(modelSelector)")
            modelEntity.generateCollisionShapes(recursive: true)
            uiView.installGestures(.all, for: modelEntity)
            let anchor  = AnchorEntity(plane: .any)
            anchor.addChild(modelEntity)
                
            uiView.scene.addAnchor(anchor)
            
        }
    // reset anchor
    if reset == true {
        
        uiView.scene.anchors.removeAll()
        
        }
      
        //MARK: saveload
            if save == true {
            uiView.session.getCurrentWorldMap { (worldMap, _) in
                
                if let map: ARWorldMap = worldMap {
                    
                    let data = try! NSKeyedArchiver.archivedData(withRootObject: map,
                                                          requiringSecureCoding: true)
                    
                    let savedMap = UserDefaults.standard
                    savedMap.set(data, forKey: "WorldMap")
                    savedMap.synchronize()
                }
            }
        }
        
        if load == true {
            let storedData = UserDefaults.standard

                if let data = storedData.data(forKey: "WorldMap") {

                    if let unarchiver = try? NSKeyedUnarchiver.unarchivedObject(
                                           ofClasses: [ARWorldMap.classForKeyedUnarchiver()],
                                                from: data),
                       let worldMap = unarchiver as? ARWorldMap {

                            config.initialWorldMap = worldMap
                            uiView.session.run(config)
                    }
                }
            }
        
            //MARK:
        }

    
}

通过直接将代码编写到updateUIView函数中,我可以使用uiView代替arView.只有config常量必须在makrUIView函数之外.当我按下相应的按钮时,用于加载和保存的布尔值设置为false,但将为true:

By writing the code directly into the updateUIView function I could use the uiView instead of the arView. Only the config constant had to be outside of the makrUIView function. The Boolean for load and save are set to false but will be true, when I press the corresponding buttons:

struct SaveLoadReset: View {

    @Binding var reset: Bool
    @Binding var save: Bool
    @Binding var load: Bool
    @Binding var modelSelector: String
    
    var body: some View {
        
            
            
    //HStack für den Laden und Speichern Knopf
                    HStack(spacing: 10){
        
    //save-Button:
                        Button(action: {
                            print("DEBUG: saveButton")
                            self.modelSelector = "default"
                            self.save = true
                            print("DEBUG: save = \(self.save)")
                        })
                        {
                            Image(systemName: "square.and.arrow.up")
                                
                            .padding(20)
                            .background(Color.white)
                            .opacity(0.3)
                            .cornerRadius(20)
                            .padding(10)
                            .font(.title)
                        }
                            
                        
                        
    //load-Button:
                        Button(action: {
                            print("DEBUG: loadButton")
                            self.load = true
                            print("DEBUG: load = \(self.load)")
                        })
                        {
                            Image(systemName: "square.and.arrow.down")
                                
                            .padding(20)
                            .background(Color.white)
                            .opacity(0.3)
                            .cornerRadius(20)
                            .font(.title)
                        }
                        
                        

                        Spacer()
                        
    //reset-Button:
                        Button(action: {
                            
                            print("DEBUG: removeButton")
                            self.reset = true
                            
                            print("DEBUG: reset = \(self.reset)" )
                            
                            
                        })
                        {
                            Image(systemName: "arrow.clockwise.circle")
                                
                            .padding(20)
                            .background(Color.white)
                            .opacity(0.3)
                            .cornerRadius(20)
                            .font(.title)
                            .padding(10)
                        }
                        
                    }
    }
}

到目前为止,我还没有收到任何错误消息,但是我的代码似乎无法正常工作.我可以按按钮,但是重新启动应用程序后,不会重新加载模型和锚点.

I don't get any error messages so far, but my code does not seem to work. I can press the buttons, but the models and anchors do not get reloaded after restarting the app.

推荐答案

您的代码可能如下所示:

Your code might look like this:

import RealityKit
import SwiftUI
import ARKit

struct ARViewContainer: UIViewRepresentable {

    @Binding var saved: Bool
    @Binding var loaded: Bool
    
    let anchor = AnchorEntity(world: [0, 0,-2])
    let arView = ARView(frame: .zero)
    let config = ARWorldTrackingConfiguration()
    
    func makeUIView(context: Context) -> ARView {
        
        let sphere = MeshResource.generateSphere(radius: 1)
        let sphereEntity = ModelEntity(mesh: sphere)
        sphereEntity.name = "SPHERE"
        sphereEntity.setParent(anchor)
        arView.scene.anchors.append(anchor)
        return arView
    }        
    fileprivate func saveWorldMap() {
        print("SAVED")
        DispatchQueue.main.async {
            saved = false
        }
    }
    fileprivate func loadWorldMap() {
        print("LOADED")
        DispatchQueue.main.async {
            loaded = false
        }
    } 
   
    func updateUIView(_ uiView: ARView, context: Context) {
        
        // Retrieve the entity from your scene
        guard let entity = uiView.scene.findEntity(named: "SPHERE")
        else { return }
                        
        if saved {
            self.saveWorldMap()
        }
        if loaded {
            self.loadWorldMap()
        }
    }
}

struct ContentView : View {
    
    @State private var saver = false
    @State private var loader = false
    
    var body: some View {
        VStack {
            ARViewContainer(saved: $saver, loaded: $loader)
            HStack {
                Spacer()
                Button(action: { self.saver.toggle() }) {
                    Text("Save")
                }
                Spacer()
                Button(action: { self.loader.toggle() }) {
                    Text("Load")
                }
                Spacer()
            }
        }
    }
}

saveWorldMap()和 loadWorldMap()方法的内容可能是这样的:

The content of saveWorldMap() and loadWorldMap() methods might be like that:

fileprivate func saveWorldMap() {

    arView.session.getCurrentWorldMap { (worldMap, _) in
        
        if let map: ARWorldMap = worldMap {
            
            let data = try! NSKeyedArchiver.archivedData(withRootObject: map, 
                                                  requiringSecureCoding: true)
            
            let savedMap = UserDefaults.standard
            savedMap.set(data, forKey: "WorldMap")
            savedMap.synchronize()
        }
    }
}

fileprivate func loadWorldMap() {

    let storedData = UserDefaults.standard

    if let data = storedData.data(forKey: "WorldMap") {

        if let unarchiver = try? NSKeyedUnarchiver.unarchivedObject(
                               ofClasses: [ARWorldMap.classForKeyedUnarchiver()],
                                    from: data),
           let worldMap = unarchiver as? ARWorldMap {

                config.initialWorldMap = worldMap
                arView.session.run(config)
        }
    }
}

这篇关于如何在SwiftUI应用中保存和加载ARWorldMap?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆