【问题标题】:ARKit - How to load .scn and texture file from server URLARKit - 如何从服务器 URL 加载 .scn 和纹理文件
【发布时间】:2018-07-16 03:05:59
【问题描述】:

我尝试在 ARKit 应用程序中从服务器 URL 动态加载 .scn 和纹理文件。我已经实现了从 web url this 方式加载 .scn 文件。但运行后我在设备上看不到任何纹理。我收到以下错误消息。

ARKitExample[3016:995067] [SceneKit] Error: Failed loading : <C3DImage 0x1d42e1980 src:file:///var/containers/Bundle/Application/622ACF79-2318-4953-A9AE-9A7F2B453AFB/ARKitExample.app/textures/lamp_DIFFUSE.png [0.000000x0.000000]>
ARKitExample[3016:995067] [SceneKit] Error: Failed loading : <C3DImage 0x1d00fe800 src:file:///var/containers/Bundle/Application/622ACF79-2318-4953-A9AE-9A7F2B453AFB/ARKitExample.app/textures/lamp_NORMAL.png [0.000000x0.000000]>
ARKitExample[3016:995067] [SceneKit] Error: Failed loading : <C3DImage 0x1d40ff800 src:file:///var/containers/Bundle/Application/622ACF79-2318-4953-A9AE-9A7F2B453AFB/ARKitExample.app/textures/lamp_METALLIC.png [0.000000x0.000000]>
ARKitExample[3016:995067] [SceneKit] Error: Failed loading : <C3DImage 0x1d42e0d80 src:file:///var/containers/Bundle/Application/622ACF79-2318-4953-A9AE-9A7F2B453AFB/ARKitExample.app/textures/lamp_ROUGHNESS.png [0.000000x0.000000]>
ARKitExample[3016:995067] [SceneKit] Error: Failed loading : <C3DImage 0x1d02e2e00 src:file:///var/containers/Bundle/Application/622ACF79-2318-4953-A9AE-9A7F2B453AFB/ARKitExample.app/textures/lamp_SHADOW.png [0.000000x0.000000]>

如何解决这个问题。谢谢

@Xartec 我试过你提到的方法,但我没有得到任何回应。我该如何解决?

let urlString = "\("https://d533c2fd.ngrok.io/")\("mode")"
        let url = URL.init(string: urlString)
        let request = URLRequest(url: url!)
        let session = URLSession.shared
        let downloadTask = session.downloadTask(with: request,
                completionHandler: { (location:URL?, response:URLResponse?, error:Error?)
                -> Void in
                print("location:\(String(describing: location))")
                let locationPath = location!.path
                  //  let documents:String = NSHomeDirectory() + "/Documents/"+"\(self.modelName).\(self.fileExtension)"
                   // let documents:String = NSHomeDirectory() + "/Documents/"+"\("model5").\("scn")"
                    let documents:String = NSHomeDirectory() + "/Documents/"+"\("mode")"

                ls = NSHomeDirectory() + "/Documents"
                let fileManager = FileManager.default
                if (fileManager.fileExists(atPath: documents)){
                     try! fileManager.removeItem(atPath: documents)
                }
                try! fileManager.moveItem(atPath: locationPath, toPath: documents)
                print("new location:\(documents)")
                let node = SCNNode()

                    do {
                        let documentss = documents + "\("model5").\("scn")"
                        let scene = try SCNScene(url: URL(fileURLWithPath: documentss), options: [.overrideAssetURLs: true])
                        let nodess = scene.rootNode.childNode(withName: "SketchUp", recursively: true)
                        node.addChildNode(nodess!)
                        self.addChildNode(node)
                        self.modelLoaded = true

                    } catch {}

        })
        downloadTask.resume()

【问题讨论】:

  • @Xartec 这是重复的......但是,早期的提问者没有找到解决纹理无法从远程 URL 动态加载的 scn 文件的问题的解决方案。有什么想法吗?
  • 解决方案在该问题的第一个也是唯一的答案中描述,在 OP 说他没有找到解决方案一周后发布:“你应该下载文件及其纹理,然后加载场景。请注意,.scn 文件和纹理应该在同一个目录中,除非您想添加一些加载选项。”
  • @Xartec 我已经更新了我的问题,请检查。
  • 我负责下载一个包含 3D 模型(在我的例子中是 mtl/obj)和所有需要的纹理的 zip。回家后我会发布相关代码

标签: ios swift arkit scnnode scnscene


【解决方案1】:

这是相关代码。我使用 Alamofire 从服务器下载并使用 ZIPFoundation 进行解压缩。就我而言,我使用 mtl/obj 文件,但使用 scn 或 dae 也应该可以正常工作。

let modelsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

func loadNodeWithID(_ id: String, completion: @escaping (SCNNode?) -> Void) {
    // Check that assets for that model are not already downloaded
    let fileManager = FileManager.default
    let dirForModel = modelsDirectory.appendingPathComponent(id)
    let dirExists = fileManager.fileExists(atPath: dirForModel.path)
    if dirExists {
        completion(loadNodeWithIdFromDisk(id))
    } else {
        let dumbURL = "http://yourserver/yourfile.zip"
        downloadZip(from: dumbURL, at: id) {
            if let url = $0 {
                print("Downloaded and unzipped at: \(url.absoluteString)")
                completion(self.loadNodeWithIdFromDisk(id))
            } else {
                print("Something went wrong!")
                completion(nil)
            }
        }
    }
}

func loadNodeWithIdFromDisk(_ id: String) -> SCNNode? {
    let fileManager = FileManager.default
    let dirForModel = modelsDirectory.appendingPathComponent(id) 
    do {
        let files = try fileManager.contentsOfDirectory(atPath: dirForModel.path)
        if let objFile = files.first(where: { $0.hasSuffix(".obj") }) {
            let objScene = try? SCNScene(url: dirForModel.appendingPathComponent(objFile), options: nil)
            let objNode = objScene?.rootNode.firstChild()
            return objNode
        } else {
            print("No obj file in directory: \(dirForModel.path)")
            return nil
        }
    } catch {
        print("Could not enumarate files or load scene: \(error)")
        return nil
    }
}

func downloadZip(from urlString: String, at destFileName: String, completion: ((URL?) -> Void)?) {
    print("Downloading \(urlString)")
    let fullDestName = destFileName + ".zip"

    let destination: DownloadRequest.DownloadFileDestination = { _, _ in
        let fileURL = modelsDirectory.appendingPathComponent(fullDestName)
        return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
    }

    Alamofire.download(urlString, to: destination).response { response in
        let error = response.error
        if error == nil {
            if let filePath = response.destinationURL?.path {
                let nStr = NSString(string: filePath)
                let id = NSString(string: nStr.lastPathComponent).deletingPathExtension
                print(response)
                print("file downloaded at: \(filePath)")
                let fileManager = FileManager()
                let sourceURL = URL(fileURLWithPath: filePath)
                var destinationURL = modelsDirectory
                destinationURL.appendPathComponent(id)
                do {
                    try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
                    try fileManager.unzipItem(at: sourceURL, to: destinationURL)
                    completion?(destinationURL)
                } catch {
                    completion?(nil)
                    print("Extraction of ZIP archive failed with error: \(error)")
                }
            } else {
                completion?(nil)
                print("File path not found")
            }
        } else {
            // Handle error
            completion?(nil)
        }
    }
}

【讨论】:

  • @leandrodemarcoi 将尽快检查和更新。谢谢
  • 我如何调用这个方法 func loadNodeWithID(_ id: String, completion: @escaping (SCNNode?) -> Void) {
  • 我已经尝试了你的代码,但仍然没有加载纹理 objFile===== model.scn objFile===== file:///var/mobile/Containers/Data/Application/455027C2- 41EB-4FD5-97CF-59156B9469C7/Documents/House/model.scn 2018-02-09 12:22:40.760478+0530 ARKitExample[5654:2247542] [SceneKit] 错误:加载失败:
  • 感谢您的回复..这是我的模型和纹理服务器 url ac5ee9f8.ngrok.io/House.zip。谢谢
  • 嘿@Raj 这段代码适合你吗?您是否必须将$0.hasSuffix(".obj") 更改为其他内容(例如“scn”)?
猜你喜欢
  • 2018-07-01
  • 2019-09-26
  • 2021-02-07
  • 2018-05-20
  • 2019-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多