Split bmesh by material

I’ve got a bmesh that I’ve created from an object and I need to export it into mesh buffers seperated by material for my engine. Is there any way to split a bmesh by material like using P in edit mode does? I’ve searched around, but I could never find any good method of doing it. Does anyone know of a way to do this?

3DModelerMan,
Go to edit mode and select all faces and clic P separate ->by materials
simply! Return in Object mode and you have x nber objects of your original by material!
Bye bye and good blend.
Spirou4D

Edit: But what do you want to say Bmesh? NURBs?
Blender use bmesh now on all faces and it’s not different as a quad face!

No, I created a bmesh from an object using the from_object method of the Python API so that I could apply all modifiers and triangulate it. I want to split the temporary mesh by material.

I repeat my question: What is “mesh buffers” and what do you want to say “Bmesh” for you, please?

I’ll just post my code so it’s a little easier to get my question across. I get a bmesh from the object I’m trying to save, but I want to be able to split it up by material.

def saveMeshComponent(context, props, obj):
#Create temporary mesh with modifiers applied
bm = bmesh.new();
bm.from_object(obj, bpy.context.scene, deform=False, render=True);

bmesh.ops.triangulate(bm, faces=bm.faces);

#I'd like to be able to seperate my mesh by material here...

bm.free();
del bm;

#Create mesh component
meshComp = {
	"Range": float(obj.data.distance),
	"Cast Shadows": obj.data.shadow_method != 'NOSHADOW'
};

return meshComp;

You must separate your bmesh after your method “saveMeshComponent()” and apply modifiers, use the result and apply:



def execute(self, context):        if bpy.context.mode != 'EDIT':            #if not in edit mode
            bpy.ops.object.editmode_toggle()      #enters in edit mode
            bpy.ops.mesh.separate(type='MATERIAL')   #separate it by material parts
            bpy.ops.object.editmode_toggle()      #exit edit mode
        else :                                    #else
            bpy.ops.mesh.separate(type='MATERIAL')   #separate it by material parts
        
        self.report({'INFO'}, "Mesh separated")
        return{'FINISHED'}

-> “BMesh is a NON-MANIFOLD boundary representation.”
you must go out this non-manifold structure for separate them.

Is there any way to access the objects created by the separate operator? I want to run the operator on a temporary duplicate object, and then save the resulting split up objects and delete them when I’m done. The documentation for ops says it returns a set with the return code, but it doesn’t have anything about the accessing operator’s results.

Why temporary duplicate object?

>>>" it returns a set with the return code"
Open Notepad+ and go to “search and replace” and make a search in directory with “mesh.separate(type=‘MATERIAL’)” in your extern or normal/contrib add-ons and you will find all addons that use this operator. You can understand his behavior.

Prefer the normal/contrib add-ons because the coder of Blender are more accurate.

  • “meshComp = {
    “Range”: float(obj.data.distance),
    “Cast Shadows”: obj.data.shadow_method != ‘NOSHADOW’
    };”

It return a distance range(a float number) and a bool value for cast shadow AND the mesh.

make sure you clear object selection, then make the object you want to separate material active and selected.

after the operator call, all new objects will be selected (bpy.context.selected_objects)

Function bmesh.ops.split is not usable yet.
Following method maybe not efficient. It makes whole bmesh copy in material loop, then remove faces with other materials.

def split_bmesh_by_material(ob):
    # Get mesh of target object
    me = ob.data
    print ('Count of mesh faces: ', len(me.polygons))
    # we want to know how many materials assigned to this mesh  
    mat_count = len(me.materials)
    
    #Create multiple temporary bmesh with modifiers applied
    bms = []
    
    # split bms by materials
    for mat_i in range (0, mat_count):  
      bms.append(bmesh.new())
      bms[mat_i].from_object(ob, bpy.context.scene, deform=False, render=True)
      # remove faces with other materials
      for f in bms[mat_i].faces:
        if f.material_index != mat_i:
          bms[mat_i].faces.remove(f)
      
    for bm_i in range (0, mat_count):
      print ('bm ', bm_i, 'count of faces: ', len(bms[bm_i].faces))
      bmesh.ops.triangulate(bms[bm_i], faces=bms[bm_i].faces);
      print ('bm ', bm_i, 'count of triangulated faces: ', len(bms[bm_i].faces))

    # maybe do bms exporting here ...
    
    # at the end, release the memory
    for bm in bms:
      bm.free();
      
    return