objective-cswiftscenekit

Dividing MDLMesh into multiple SCNGeometry


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:

  1. I tried to use [MDLMes newSubdividedMesh: aMesh submeshIndex: i subdivisionLevels:0] for each of the sub meshes. Then I created SCNGeometry out of them.
    The problem was that SceneKit didn't render the scene as expected. The geometry was working but the light was not applied to the model, something that worked when I was converting the whole 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 MDLMeshrendering the whole mesh. Notice the missing light effects on the first rendering with the above code.

  1. 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.


Solution

  • [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?