Apply .jpg and .mtl file to .obj file in SceneKit

8.7k views Asked by At

The designer has delivered three files:

  • image.jpg
  • something.mtl
  • whatever.obj

I can successfully load the .obj file into my scene like such:

  SCNView * sceneView = [SCNView new];
  sceneView.frame = view.bounds;
  [view addSubview:sceneView];

  SCNScene * scene = [SCNScene sceneNamed:@"models.scnassets/whatever.obj"];
  [sceneView setScene:scene];

What I'm struggling with is applying the .jpg and .mtl files to the .obj file. I've tried applying the image with the following code, but no love:

SCNMaterial * material = [SCNMaterial material];
material.diffuse.contents = [UIImage imageNamed:@"image.jpg"];

SCNNode * materialNode = [SCNNode node];
materialNode.geometry.firstMaterial = material;
[scene.rootNode addChildNode:materialNode];
3

There are 3 answers

0
Zeeshan Arif On

I run into the same problem and only solution i found is in this link Click here. I could load the .mtl information was to create the object through scene

let scene = SCNScene(named: "rose.obj")

Make sure to have the .mtl and the jpg with the textures in your bundle.

1
Nirmal Bajpai On

Hi @Johnny There are multiple ways to apply texture files on .obj file.

  1. If you want to load some .obj files with awesome customizations you can open .obj file in Xcode and Apply Textures(Diffuse Map, Normal Map etc, Environments and Lights Camera also) then .obj file will convert .scn file to use in SCNView.

  2. If you want to apply textures/change textures on specific node of .obj or .scn file dynamically you may Use Model I/O Framework which provides Import, export, and manipulate 3D models using a common infrastructure that integrates MetalKit, GLKit, and SceneKit. SceneKit provides classes for ModelIO assets ex..+ (instancetype)sceneWithMDLAsset:(MDLAsset *)mdlAsset;(as @Zeeshan answered).

  3. Your designer may exports 3D model files in .dae formate. In .dae file a single file contains texture, camera, light reference. No .mtl or others file needed as you use in .obj. .dae also supported in SCNKit

  4. If you uses metal rendered you can load textures directly from NSURL.

0
Johnny Rockex On

This has gotten me some of the way there, albeit without using the .mtl file:

//START 3D
    NSURL * url = [[NSBundle mainBundle] URLForResource:@"playerModel" withExtension:@"obj"];
    MDLAsset * asset = [[MDLAsset alloc] initWithURL:url];
    MDLMesh * object = (MDLMesh *)[asset objectAtIndex:0];

    MDLScatteringFunction * scatFunction = [MDLScatteringFunction new];
    MDLMaterial * material = [[MDLMaterial alloc] initWithName:@"playerMaterial" scatteringFunction:scatFunction];

    NSURL * materialURL = [[NSBundle mainBundle] URLForResource:skinFilename withExtension:@"jpg"];
    MDLMaterialProperty * baseColour = [MDLMaterialProperty new];
    [baseColour setType:MDLMaterialPropertyTypeTexture];
    [baseColour setSemantic:MDLMaterialSemanticBaseColor];
    [baseColour setURLValue:materialURL];
    [material setProperty:baseColour];

    for (MDLSubmesh * sub in object.submeshes){
        sub.material = material;
    }

    SCNScene * scene = [SCNScene new];
    SCNNode * node = [SCNNode nodeWithMDLObject:object];
    SCNVector3 v = SCNVector3Make(100, 200, 0);
    [node setPosition:v];
    [scene.rootNode addChildNode:node];

    SCNView * view = [SCNView new];
    view.frame = transferInView.bounds;
    view.autoenablesDefaultLighting = true;
    view.allowsCameraControl = false;
    view.scene = scene;
    view.backgroundColor = [UIColor clearColor];
    [transferInView addSubview:view];

    SCNAction * rotate = [SCNAction rotateByX:0 y:1 z:0 duration:1.0f];
    [node runAction:[SCNAction repeatActionForever:rotate]];

    SCNVector3 min = SCNVector3Zero;
    SCNVector3 max = SCNVector3Zero;
    [node getBoundingBoxMin:&min max:&max];
    node.pivot = SCNMatrix4MakeTranslation((max.x - min.x) / 2 + min.x, (max.y - min.y) / 2 + min.y, 0);

    //END 3D