Is there such a script already.

Before reinventing the wheel…

I would like to be able to edit the meshes of a group of object as if it were one single mesh. If such a script exist (or even one that only needs to be modified) the nice! Otherwise I think that one could work like this.

Imagine a generic drawer made of 5 objects: bottom, 2 sides, front and back. I’d like to be able to join all those parts in a single mesh, while creating 5 vertex groups, one for each joined object, each named the same as the corresponding object they come from.

Ideally, the reverse operation would be possible: separate that object by vertex groups and give the vertex group name for to each new object created.

Do you find any fault into that algorithm ?

Thanks for reading this. :slight_smile:

Wait, you want to edit all the meshes in a group or want a script that makes all the meshes in a group one mesh (w/pieces assigned to a vertex group?

I want to edit all mesh objects selected, as a group or otherwise as if they were one single object.

Joining them temporarily is already possible but then the objects loose their names when they are separated back into objects.

Although I haven’t seen a script like this, there may be one that fulfils your request.
However, a hacky solution:

1)Get all the positions of each vertex, and store them in a dict:

{
vertex_position : None,
}

2)Duplicate the objects, and join them together, so you have a group.
3)For each vertex position in the dictionary, match the position in the joined mesh to the vertex
So it looks like this:

{
vertex_position : joined_vertex,
}

4)Transform the mesh as you wish, then make another dictionary, which matches the original positions to the new positions, using the position of the stored ‘joined vertex’

{
vertex_original_position : vertex_new_position
}

Done!

Thanks Agoose, your suggestions are opening all sort of avenues for me.

In the meanwhile, the lack of reactions here forced me to find a way by myself. I’ll let you know how it turns out.

OK, here’s what came up: it is my first foray into bpy beyond a one liner so, please, do not refrain your critics. I need to learn.

import math
import bpy
import mathutils

def filterForMeshes():

    selectedMeshes=[]    
    #make a list of all that is selected
    selection=bpy.context.selected_objects

    #test each object to see if they are meshes
    for i in range(0,len(selection)):
        #if they are, append to selectedMeshes
        if selection[i].type == 'MESH':
            selectedMeshes.append(selection[i])

    return selectedMeshes

def makeVGs(selectedMeshes):
    #for each of the selected meshes in turn
    for i in range(0,len(selectedMeshes)):
        # make it active
        bpy.context.scene.objects.active=selectedMeshes[i]
        # go into edit mode
        bpy.ops.object.mode_set(mode='EDIT')
        vg=bpy.context.object.vertex_groups
        # add the name of the object as a prefix to existing vertex groups
        for n in range(0,len(vg)):
            vg[n].name= selectedMeshes[i].name +"_"+ vg[n].name
        # select all vertices
        bpy.ops.mesh.select_all(action='SELECT')
        # create a new vertex group with the 'All_' prefix
        bpy.context.object.vertex_groups.new('All_'+selectedMeshes[i].name)
        # make that group active
        bpy.ops.object.vertex_group_set_active(group='All_'+selectedMeshes[i].name)
        # assign the selected vertices to the new vg
        bpy.ops.object.vertex_group_assign()
        bpy.ops.object.mode_set(mode='OBJECT')
        

def separateObjects():
    # be sure to be in edit mode
    bpy.ops.object.mode_set(mode='EDIT')
    # deselect all vertices
    bpy.ops.mesh.select_all(action='DESELECT')
    
    # To separate each object:
    
    # find all vertex groups
    VGs=list(bpy.context.active_object.vertex_groups)
    
    # find VGs which start by 'All_'
    all=[]
    for vg in range(0,len(VGs)):
        vgName=VGs[vg].name
        if vgName[0:4]=='All_':
            all.append(VGs[vg])
            
    # Select each 'All_' VGs, separate, name, repeat
    
    # take note of all the objects in the scene:
    objects=list(bpy.data.objects)
    for vg in range(0,len(all)):
        bpy.ops.object.vertex_group_set_active(group=all[vg].name)
        # select its assigned vertices.
        bpy.ops.object.vertex_group_select()
        # complete selection in case object was edited
        bpy.ops.mesh.select_linked(limit=False)
        # separate the object
        bpy.ops.mesh.separate(type='SELECTED')
        # in Object mode...
        bpy.ops.object.mode_set(mode='OBJECT')
        # ... find the new object
        objectsPlusOne=list(bpy.data.objects)
        diff_list = [item for item in objectsPlusOne if not item in objects]
        # name new object
        diff_list[0].name=all[vg].name[4:]
        # take note of active object
        tempActive=bpy.context.scene.objects.active
        # set new object as active
        bpy.context.scene.objects.active = diff_list[0]
        # gather VGs of new object in a list
        vgInNewObject=list(bpy.context.active_object.vertex_groups)
        # remove all vgs not related to the object
        for i in range(0,len(vgInNewObject)):
            if diff_list[0].name not in vgInNewObject[i].name:
                bpy.ops.object.vertex_group_set_active(group=vgInNewObject[i].name)
                bpy.ops.object.vertex_group_remove(all=False)
            elif vgInNewObject[i].name[0:4] == 'All_':
                bpy.ops.object.vertex_group_set_active(group=vgInNewObject[i].name)
                bpy.ops.object.vertex_group_remove(all=False)                
        # make the rest of the joined object active
        bpy.context.scene.objects.active=tempActive
        # set 'objects' to 'ObjectsPlusOne
        objects = objectsPlusOne
        # back in Edit mode
        bpy.ops.object.mode_set(mode='EDIT')

    return


 
class AFO_OFAPanel(bpy.types.Panel): 
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    bl_label = "3 Musketeers"
 
    def draw(self, context) :
        TheRow = self.layout.row(align = True)
        TheRow.operator("mesh.object_multi_edit", text = "AFO")
        TheRow2 = self.layout.column(align = True)
        TheRow2.operator("mesh.object_multi_separate", text = "OFA")
    #end draw
 
#end OFA_AFO_MakerPanel
 
class MeshObjectMultiEdit(bpy.types.Operator) :
    bl_idname = "mesh.object_multi_edit"
    bl_label = "Edit Multi"
    bl_options = {"UNDO"}
     
    def invoke(self, context, event) :
        meshesToEdit=filterForMeshes()
        makeVGs(meshesToEdit)
        try:
            bpy.ops.object.join()
        except RuntimeError:
            print("There is no mesh selected")
        return {"FINISHED"}
    #end invoke
 
class MeshObjectSeparateMulti(bpy.types.Operator) :
    bl_idname = "mesh.object_multi_separate"
    bl_label = "Multi Separate"
    bl_options = {"UNDO"}
     
    def invoke(self, context, event) :
        separateObjects()
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        bpy.context.active_object.select=True
        bpy.ops.object.delete()
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
        return {"FINISHED"}
    #end invoke
 
#end MakeTetrahedron

bpy.utils.register_class(MeshObjectSeparateMulti)

bpy.utils.register_class(MeshObjectMultiEdit)

bpy.utils.register_class(AFO_OFAPanel)

It works fine. I guess that I should use a little exception handling, for the sake of my co-workers.
For the moment I keep it in the text editor by default, having it registering using the check-box.

@ agoose77: I couldn’t differentiate between vertices that sat at the same location using your method. Also I didn’t find how to take into account vertices that were added while editing. You taught me good nevertheless, so thanks a bunch. :slight_smile:

If there is interest, I could make a video to show how I use it.