How to load a model and textures from a remote server using ARKit?

我们两清 提交于 2021-02-09 11:00:09

问题


I am working on an ARKit app using Swift in Xcode trying to load models from a remote server but am having an issue getting the model and the textures / materials to load together and have the textures / materials display correctly.

I have gone through a few links and tutorials and get the model to load but the materials do not show. I have created models in the scene editor, or downloaded them and converted to .scn files, locate them in Finder and then uploaded them to a web-server. Just the .scn file and material (images).

//Tap Gesture 
@objc func handleTap(_ gesture: UITapGestureRecognizer) {

    //hittest
    let results = self.sceneView.hitTest(gesture.location(in: gesture.view), types: ARHitTestResult.ResultType.featurePoint)

    //return first tap
    guard let result: ARHitTestResult = results.first else {
        return
    }

    //Set URL of location of model
    let myURL = NSURL(string: "https://www.website.com/scnfiles/iPhoneX.scn")

    //Try getting this url or return 
    guard let scene = try? SCNScene(url: myURL! as URL, options: nil) else {return}

    //Set the node to be the model
    let node = scene.rootNode.childNode(withName: "SketchUp", recursively: true)

    //Set scale
    node?.scale = SCNVector3(0.025,0.025,0.025)

    //The material image is located in the same directory
    node?.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "https://website/scnfiles/iPhoneX_Screen.jpg")

    //set the position of the model
    let position = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)
        node?.position = position

    //Add to scene
    self.sceneView.scene.rootNode.addChildNode(node!)
}

I would like the model to load correctly as it would locally, showing the model with the applied textures but instead I get the model with no textures, just colors or white where the material is expected.

I receive the following error which looks like it is trying to load it locally?

ARKitModels[10386:3406637] [SceneKit] Error: Failed to load : <C3DImage 0x281e45180 src:file:///var/containers/Bundle/Application/233AE78F-748F-420B-96AD-30F591ADF80C/ARKitModels.app/material/iPhoneX_Screen.jpg [0.000000x0.000000]>

Any help is appreciated and if there is a better way to do this please let me know. Thank you!


回答1:


So, since I want to load everything from a remote server, nothing locally here is what I came up with thanks to some help from @ATV.

Solution: Loop though child nodes and set texture to the same name as the node.name. You can set the name of the node in scene editor and then have the same named image files in the proper folder. This allows for dynamic loading. This only works if you have control over the models / server or have explicit instructions.

@objc func handleTap(_ gesture: UITapGestureRecognizer) {

    let results = self.sceneView.hitTest(gesture.location(in: gesture.view), types: ARHitTestResult.ResultType.featurePoint)

    guard let result: ARHitTestResult = results.first else {
        return
    }

    let myURL = NSURL(string: "https://www.website.com/scnfiles/model/model.scn")

    guard let scene = try? SCNScene(url: myURL! as URL, options: nil) else {
        return
    }

    let node = scene.rootNode.childNode(withName: "SketchUp", recursively: true)

    // Solution //
    let children = (node?.childNodes)!

    for child in children {
        child.geometry?.materials.forEach{$0.diffuse.contents = "https://www.website.com/scnfiles/model/materials/" + child.name! + ".jpg"
    }

    node?.scale = SCNVector3(0.025, 0.025, 0.025)

    let position = SCNVector3Make(result.worldTransform.columns.3.x, 
                                  result.worldTransform.columns.3.y, 
                                  result.worldTransform.columns.3.z)
    node?.position = position
    self.sceneView.scene.rootNode.addChildNode(node!)
}



回答2:


Try to set pre-downloaded UIImage as contents to all materials from your geometry. Something like:

geometry.materials.forEach{$0.diffuse.contents = textureImage}


来源:https://stackoverflow.com/questions/56039590/how-to-load-a-model-and-textures-from-a-remote-server-using-arkit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!