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.
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’
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.
If there is interest, I could make a video to show how I use it.