I have an .obj file containing a 3D model, divided into multiple smaller meshes, e.g. a front and a back.
My goal is to load this file into a SceneKit View and interact with the different parts of the model, to color them, select them, hide them, or move them individually.
I was able to load the file into a MDLAsset
, containing the MDLMesh
, which itself contains all of the sub meshes as MDLSubmesh
.
To display the loaded model I have to convert the MDLMesh
to an SCNGeometry
.
The basic approach is to call SCNGeometry geometryWithMDLMesh:(MDLMesh *)mdlMesh
. This works fine, the SCNGeometry
contains different SCNGeometryElements
.
However, a lot of information that was in the MDLSubmesh
is lost when converting this to the Scene Kit Geometry and my ability to interact with the different sub meshes is very limited.
It would be ideal if I convert all of the MDLSubmesh
to SCNGeometry
individually. I have tried two different approaches:
[MDLMes newSubdividedMesh: aMesh submeshIndex: i subdivisionLevels:0]
for each of the sub meshes. Then I created SCNGeometry
out of them.MDLMesh
.Generate a new mesh from each submesh:
for (NSInteger i = 0; i < [[mesh submeshes] count]; i++) {
MDLMesh *submesh = [MDLMesh newSubdividedMesh:mesh submeshIndex:i subdivisionLevels:0];
SCNGeometry *geometry = [SCNGeometry geometryWithMDLMesh:submesh];
SCNNode *subNode = [SCNNode nodeWithGeometry:geometry];
[node addChildNode:subNode];
}
The resulting rendering with this approach rendering with subdivided meshes and when converting the whole MDLMesh
rendering the whole mesh. Notice the missing light effects on the first rendering with the above code.
The second approach was to generate the SCNGeometry
with the SCNGeometry geometryWithSources:elements:
method. Although I doubt this is the 'right' way to do this, here is what I tried.
(SCNNode*) loadMDLMesh : (MDLMesh*) mesh withSubmeshes: (bool) sub { if (sub) { //Generate a scene kit node SCNNode * node = [SCNNode node];
//Generate a new mesh from each submesh
for (NSInteger i = 0; i < [[mesh submeshes] count]; i++) {
//Create the geometry element from the mdl sub mesh
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithMDLSubmesh: [[mesh submeshes] objectAtIndex:i] ];
//Create a geometry source from the index buffer
MDLMeshBufferMap *map = [[[[mesh submeshes] objectAtIndex:i] indexBuffer] map];
SCNGeometrySource *source = [SCNGeometrySource geometrySourceWithVertices:[map bytes] count:[[[mesh submeshes] objectAtIndex:i] indexCount]];
//Create the SCNGeometry from the source and the element
SCNGeometry *subMesh = [SCNGeometry geometryWithSources:[NSArray arrayWithObject:source] elements:[NSArray arrayWithObject:element]];
//Update the name
subMesh.name = [[[mesh submeshes] objectAtIndex:i] name];
//Create a subnode and add it to the object node
SCNNode *subNode = [SCNNode nodeWithGeometry:subMesh];
[node addChildNode:subNode];
}
return node;
} else {
return [SCNNode nodeWithMDLObject:mesh];
}
Unfortunately, the app crashes with an Bad Access Exception.
As one can see, I am not that experienced with developing objective-c. Any help to fix my ideas or different approaches to subdivide the mesh would be great.
Thank you.
[Re-posting comment as answer as it seems it provided a working solution]
I looks like you're missing the normals when using +newSubdividedMesh:submeshIndex:subdivisionLevels:
to build a new mesh from a submesh. Maybe -initWithVertexBuffer:vertexCount:descriptor:submeshes:
will lead to better results?