4

I am new to this. And there comes my first problem.

I build an object loader with SceneKit. I got the path, the Object is available, but I have no clue how I can color the shown object.

ScnScene *testScene = [SCNScene sceneWithURL:url options:nil error:NULL];
testScene.background.contents = [UIImage imageWithName:@"color.png"];

[self.mainView.scene.rootnode addChildNode:testScene.rootNode];

This didn't work. I also tried with:

SCNMaterialProperty *testColor = [SCNMaterialProperty materialPropertyWithContents [UIImage imageNamed:@"color.png"]];
testScene.rootnode.geometry.materials = testcolor;

Or:

SCNMaterial *testColor = [SCNMaterial material];
testColor.diffuse.contesnts = [UIColor redColor];
testScene.rootnode.geometry.firstMaterial = testColor;

Nothing works. When I start the app, every object is displayed. So far the OBJ-Loader works out very well. But everything is still gray. I totally have no clue how to color the displayed objects. Has anyone a hint/idea/solution for me?

Btw. I want to avoid that I have to build a geometry out of the OBJ-Informations manually. So I try to solve this by the SCNScene.

Alexander Langer
  • 320
  • 2
  • 11

2 Answers2

7

The major problem was that the import by a SCNScenedoes not work that way. So the right solution is to import the obj.file into a SCNNode, add a SCNMaterial with the chosen color (or an image) to the SCNNode and give the SCNNodeto the SCNScene. To load the obj.file, you need to import that by Model IO Framework.

I will give some code how I made it colorful.

#import <SceneKit/SceneKit.h>
#import <ModelIO/ModelIO.h>
#import <SceneKit/ModelIO.h>

...

@property (nonatomic) SCNView* mainView;

....

MDLAsset *asset = [[MDLAsset alloc] initWithURL:url];     
SCNScene *scene = [SCNScene scene];
SCNNode *node = [SCNNode nodeWithMDLObject:[asset objectAtIndex:0]];

SCNMaterial *material = [SCNMaterial material];
material.diffuse.contents = [UIColor colorWithHue:0 saturation:0.1 brightness:0.5 alpha:1];
node.geometry.firstMaterial = material;

[scene.rootNode addChildNode:node];
[self.mainView.scene.rootNode addChildNode:scene.rootNode];

Alternately you can add a color by this:

material.diffuse.contents = [UIImage imageNamed:@"farbe.png"];

Now you can import any obj.file externally (from any chosen folder you like) and color it.

Thanks to SGlindemann, cashmash and Hal Mueller, who helped out to find that solution.


UPDATE (29.1.2017)

Somehow the way above does not work anymore. I did not figure out yet what changed. But I made another code that makes loading for 3D files possible (from mainBundle, not externally). Here I start from a SCNNode class which is called by the ViewController.m. The SCNScene is setup in the ViewController. Following there is the code which I wrote for the SCNNode class.

Before you start, put the .obj and .mtl file (both with same name) into your Xcode project. You don't need to convert it to a scene.

#import <ModelIO/ModelIO.h>
#import <SceneKit/ModelIO.h>

...

@property (nonatomic) SCNNode *objectNode;

...

NSString* path = [[NSBundle mainBundle]
            pathForResource:[NSString stringWithFormat:@"name of the obj.file"]
            ofType:@"obj"];
NSURL *url = [NSURL fileURLWithPath:path];
MDLAsset *asset = [[MDLAsset alloc]initWithURL:url];

// Create the Block
self.objectNode = [SCNNode nodeWithMDLObject:[asset objectAtIndex:0]];


[self addChildNode: self.objectNode];

return self;

This returned self has to be added into your view.

[self.view.scene.rootNode addChildNode:returnedObj];

The MDLAssetloads the .obj-file with the corresponding .mtl-file and png-File. I used this code to load objects from MagicaVoxel (this exports obj+mtl+png at once). I did not get deep into it yet.

I did NOT try this code with external loadings or typing in colors manually via SCNMaterial. So there is no statement whether this works or not. I did not try.

Alexander Langer
  • 320
  • 2
  • 11
  • Hey, i tried this code but i am getting white screen only. No 3d model. Can you help? – Paras vora Jan 24 '17 at 05:57
  • Hey, I got the problem too. Somehow they changed something so that the external loading does not work anymore. I made another code which is working (loading via mainbundle + using .obj and .mtl file). I update the post above with my new code. I hope it helps. – Alexander Langer Jan 29 '17 at 14:35
2

Your first example will set the background of the scene but do nothing with your object.

Your second example should be giving you some compiler warnings. You're assigning a single SCNMaterialProperty to testScene.rootnode.geometry.materials, which expects an array of SCNMaterial (not SCNMaterialProperty). Is that your real code?

The final example shouldn't compile at all: you've misspelled contents as contesnts. Other than that, it ought to work.

Note that MDLAsset can import an OBJ file and return an SCNNode. See How do you convert Wavefront OBJ file to an SCNNode with Model I/O. If the object is an asset you'll be shipping with your project, save it as an SCNScene (which is compact and optimized), and ship that, not the original OBJ.

Community
  • 1
  • 1
Hal Mueller
  • 7,019
  • 2
  • 24
  • 42
  • Thank you very much for your response. I rewrote the code manually, because my laptop with the code was used by another person at that moment. There came the wrong code spelling from. Sorry for that. I used the `MDLAsset` as you suggested. Overall it doesn't work to add a color by `SCNMaterial` to a `SCNScene`, but it works if I import the obj.file to a `SCNNode`. So everything I tried on the first run were wrong. I will add the solution I found to make everything a bit more colorful. But really thank you very much. Without your `MDLAsset` insertion this problem would have driven me crazy. – Alexander Langer Feb 20 '16 at 17:20