2

I need to import 3D model from server URL but it's not working properly. Here is my code:

guard let path = modelPath, !path.isEmpty else {
    fatalError("Failed to find model file path.")
}

guard let modelURL = URL(string: path) else {
    fatalError("Failed to find model URL.")
}

let asset = MDLAsset(url:modelURL)
guard let object = asset.object(at: 0) as? MDLMesh else {
    fatalError("Failed to get mesh from asset.")
}

...crash here at object.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
iBeginner
  • 241
  • 1
  • 2
  • 8
  • So you have an url like that http://www.example.com/download/myfile.obj? Are you able to download through a browser or you get an HTTP error? – shadowsheep Feb 15 '18 at 09:34
  • url is something like "https://****1_3d-model.obj***35b679b0e04927f".Yes I am able to download it from browser without error. – iBeginner Feb 15 '18 at 09:45

2 Answers2

3

MDLAsset(url:) does not handle downloading models from a server, it's only for URLs that point to local storage.

You will have to download it yourself (using URLSession or a framework like Alamofire).

Example using URLSession:

Download task will return temporary location for the file that will be deleted after the callback closure return so if you need to reuse the file you will have to re-save it somewhere.

The tempLocation file will have an extension of .tmp, which MDLAsset will not be able to process. Even if you don't need to persist the file, I didn't come up with a better way than to re-save it with the needed extension (.obj that is).

let fileManager = FileManager.default
let localModelName = "model.obj"
let serverModelURL = URL(...)
let localModelURL = fileManager
        .urls(for: .documentDirectory, in: .userDomainMask[0]
        .appendingPathComponent(localModelName)

let session = URLSession(configuration: .default)
let task = session.downloadTask(with: modelURL) { tempLocation, response, error in
    guard let tempLocation = tempLocation else {
        // handle error
        return
    }

    do {
        // FileManager's copyItem throws an error if the file exist
        // so we check and remove previously downloaded file
        // That's just for testing purposes, you probably wouldn't want to download
        // the same model multiple times instead of just persisting it

        if fileManager.fileExists(atPath: localModelURL.path) {
            try fileManager.removeItem(at: localModelURL)
        }

        try fileManager.copyItem(at: tempLocation, to: localModelURL)

    } catch {
        // handle error
    }

    let asset = MDLAsset(url: localURL)
    guard let object = asset.object(at: 0) as? MDLMesh else {
        fatalError("Failed to get mesh from asset.")
    }
}

task.resume() // don't forget to call resume to start downloading
Lësha Turkowski
  • 1,361
  • 1
  • 10
  • 21
0

I think that .obj objects also need at least an .mlt file and probably an .jpg file for texture, check if you have an error because these files missing

Vasilis D.
  • 1,416
  • 13
  • 21
  • No .obj and .jpg is enough.I have .jpg in project.It is working properly if I fetch .obj from bundle but not working if I gave server URL for .obj – iBeginner Feb 15 '18 at 10:21
  • @iBeginner only .obj is needed to load the mesh, no textures are needed. Additionally, MDLAsset requires a local URL. You have to download the .obj yourself from the server – blueether Oct 21 '20 at 18:27