Automating mesh split process - can anyone help ?

I am looking for a script to automate the following process:

It would have to be done on all visible objects/layers.

Is it possible? Would anyone be interested in making such script? Thanks.

I doubt it’s that complex. Edges are marked manually in my case. So script should select marked edges and split mesh there, then fill up holes and split mesh into several. Basically whatever I do manually in the video should be done via script.

If the edges you want split are marked(and properly so in a way that they can actually be split into separate objects) then it would probably be pretty easy. Definitely so if you don’t need to preserve shape keys.
Don’t mean to just say that and run, but it sounded like you might want an appraisal of its difficulty as well.

So any chance someone could write a script to do the task ? :slight_smile:

I don’t think it’s that easy, because there is no efficient way to determine face groups limited by seams. There is only a select operator, but you would need to run it several times until you know all the groups. For not to complex meshes, it should still be possible - as long as filling holes can be achieved by simply running that fill operator (F key)?!

In Edit mode, with Face selection mode, if I hover mouse over the faces and press L, it will only select faces up to the marked edges. So I am hoping if it can be done manually, API has some kind of function to do that :slight_smile:

To fill holes Clean up > Fill holes can be used, or just F in Vertex selection mode. There is one case where F will create an ugly N-Gon, but F, Ctrl+T, Alt+J does excellent job fixing it :slight_smile:

Maybe there’s some aspect of this I don’t understand but I wrote something that split seams last night and it seemed fairly successful, although it wasn’t for OP’s purposes because I just wanted to split the model by its UVs period.

It might be slow, but using BMesh(assuming all the seams create fully separated mesh parts) I’d think you could just create a list of edges with seams, split them all, then operate on the newly split mesh parts by removing doubles, filling boundary edges, and separating. It seems automatable, but as you’ve said I wouldn’t say it’d be easy to program it to be efficient/fast and I don’t think it’d have many general uses.

So, any chance to get help on this subject? :slight_smile:

Maybe this works:

import bpy
ob = bpy.context.object
scene = bpy.context.scene
assert ob is not None and ob.type == 'MESH'

for obj in bpy.context.selected_objects:
    obj.select = False
ob.select = True
    
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
for edge in ob.data.edges:
    if edge.use_seam:
        edge.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.edge_split()
bpy.ops.mesh.separate(type='LOOSE')

bpy.ops.object.mode_set(mode='OBJECT')
for obj in bpy.context.selected_objects:
    scene.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action="SELECT")
    bpy.ops.mesh.fill_holes()
    bpy.ops.object.mode_set(mode='OBJECT')
    

It kinda works, it doesn’t fill upped section and it split upper part, even though there are no seams:

Btw, indeed, sharp edges didn’t work, I had to use seams.

oh yeah, it uses seems. You could change that to sharp edges of course.

A similar mesh to yours worked in my test, it filled the holes. I guess it’s highly dependent on the geometry whether the output matches your expectations.

These are my test cases:

  1. http://www.pasteall.org/blend/37011
  2. http://www.pasteall.org/blend/37012
  3. http://www.pasteall.org/blend/37013

I don’t think there can be some other case where different split would be required.

And for the second test case here is how I fill/fix splits manually:

Instead of selected objects, it would be more efficient to have done it to objects with seams on all visible layers. I might have bunch of the pieces like that when making a level and selecting every one of them would be kinda tedious.

Thanks for your help, CoDEmanX :yes:

Alright, this script works (almost):


import bpy
ob = bpy.context.object
scene = bpy.context.scene
assert ob is not None and ob.type == 'MESH'


for obj in bpy.context.selected_objects:
    obj.select = False
ob.select = True
    
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT')
for edge in ob.data.edges:
    if edge.use_seam:
        edge.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.edge_split()
bpy.ops.mesh.separate(type='LOOSE')


bpy.ops.object.mode_set(mode='OBJECT')
for obj in bpy.context.selected_objects:
    scene.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_mode(type='VERT')
    bpy.ops.mesh.select_all(action="SELECT")    
    bpy.ops.mesh.fill_holes()
    bpy.ops.mesh.remove_doubles()
    bpy.ops.mesh.quads_convert_to_tris()
    bpy.ops.mesh.tris_convert_to_quads()
    bpy.ops.object.mode_set(mode='OBJECT')

bpy.ops.mesh.fill_holes() doesn’t work for corner pieces :frowning: (doesn’t fill up adjacent faces with NGon as illustrated in the video below)


import bpy
ob = bpy.context.object
scene = bpy.context.scene
assert ob is not None and ob.type == 'MESH'


for obj in bpy.context.selected_objects:
    obj.select = False
ob.select = True
    
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT')
for edge in ob.data.edges:
    if edge.use_seam:
        edge.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.edge_split()
bpy.ops.mesh.separate(type='LOOSE')


bpy.ops.object.mode_set(mode='OBJECT')
for obj in bpy.context.selected_objects:
    scene.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_mode(type='VERT')
    bpy.ops.mesh.select_all(action="SELECT")    
    bpy.ops.mesh.fill_holes(sides=8)
    bpy.ops.mesh.remove_doubles()
    bpy.ops.mesh.quads_convert_to_tris()
    bpy.ops.mesh.tris_convert_to_quads()
    bpy.ops.object.mode_set(mode='OBJECT')

This works for test case 1 and 2, but for case 3 it doesn’t quite work (extra inner faces remain). I think case 3 is somewhat isolated instances and can be manually split into 6 separate objects. Eventually there might be more scenarios where automation is desired, but for the mean time it should work.

Now I just need to make it work with objects on visible layers, instead of selected objects.

@CoDEmanX: Could you please help with that?