3

I'm working with ModelI/O to show 3D model. This is my code:

// Load the .OBJ file
    guard let url = Bundle.main.url(forResource: "agera r", withExtension: "obj") else {
        fatalError("Failed to find model file.")
    }

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

    // Create a material from the various textures
    let scatteringFunction = MDLScatteringFunction()
    let material = MDLMaterial(name: "baseMaterial", scatteringFunction: scatteringFunction)
    let textureFileName = "agera_r.mtl"
    material.setTextureProperties([.baseColor: textureFileName])

    // Apply the texture to every submesh of the asset
    for submesh in object.submeshes!  {
        if let submesh = submesh as? MDLSubmesh {
            submesh.material = material
        }
    }

    // Wrap the ModelIO object in a SceneKit object
    let node = SCNNode(mdlObject: object)
    let scene = SCNScene()
    scene.rootNode.addChildNode(node)

    // Set up the SceneView
    sceneView.autoenablesDefaultLighting = true
    sceneView.allowsCameraControl = true
    sceneView.scene = scene
    sceneView.backgroundColor = UIColor.black
}
extension MDLMaterial {
func setTextureProperties(_ textures: [MDLMaterialSemantic:String]) -> Void {
    for (key,value) in textures {
        guard let url = Bundle.main.url(forResource: value, withExtension: "") else {
            fatalError("Failed to find URL for resource \(value).")
        }
        let property = MDLMaterialProperty(name:value, semantic: key, url: url)
        self.setProperty(property)
    }
}

The problem is when the app run, the 3D model is shown but the .mtl texture file not apply to it. How to fix this issue? Thanks all.

Duc Phan
  • 181
  • 5
  • 16

1 Answers1

0

Main problem in this lines:

let textureFileName = "agera_r.mtl"
material.setTextureProperties([.baseColor: textureFileName])

You should pass URL to the texture file instead of .mtl file URL. This code works fine for me:

OBJECTIVE-C

MDLScatteringFunction *scatFunction = [MDLScatteringFunction new];
MDLMaterial *mdlMaterial = [[MDLMaterial alloc] initWithName:@"material" scatteringFunction:scatFunction];
MDLMaterialProperty *bcProperty = [[MDLMaterialProperty alloc] initWithName:@"BaseColor" semantic:MDLMaterialSemanticBaseColor URL:textureFileURL];
[mdlMaterial setProperty:bcProperty];
SCNMaterial *material = [SCNMaterial materialWithMDLMaterial:mdlMaterial];
node.geometry.firstMaterial = material;

SWIFT

let scatFunction = MDLScatteringFunction()
let material = MDLMaterial(name: "material", scatteringFunction: scatFunction)
material.setTextureProperties(textures: [.baseColor: "model/texture.png"])
mesh.submeshes?.forEach {
    if let submesh = $0 as? MDLSubmesh {
        submesh.material = material
    }
}

baseNode = SCNNode(mdlObject: mesh)

P.S. This is two slightly different approaches to that task.

UPDATE:

let baseNode = SCNScene(named: "mesh.obj")!.rootNode

Also you can try to use this approach. If I recall correctly it will hook up .mtl file and other textures. (If path to .mtl file, which written in .obj file, is valid and paths to the textures in .mtl also valid)

Joker
  • 263
  • 2
  • 16
  • Thanks for your reply. So there is no other way than to use a png texture file instead of mtl file? – Duc Phan May 09 '18 at 03:02
  • I don't know about how to do it in runtime with .mtl file. If you can do it in design time you can manually add this .obj in .scene file and it will use .mtl file and all other textures. Also I have added another variant for you. – Joker May 09 '18 at 06:15