Hi, folks
I’m hoping someone could help me out in creating a script that let’s us transfer weights from a mesh to multiple objects. In vanilla Blender, I can only do it between two selections at a time, but since I have a ton of objects, that would be tedious, hence I’d like to script it.
I know I could simply join all the objects into one then use the transfer weights feature, but I’d like to keep them separate.
I don’t have much experience in scripting, so apologies if this is a trivial task.
For context, I’m weight painting a lower-poly cage mesh, and wanting to transfer the weights to the final mesh which is a collection of objects.
If you haven’t already, go to the user preferences (this used to be ctrl+alt+u but i guess that got changed?) -> Interface -> turn on python tooltips. This will show you the python command corresponding to each button’s action in its tooltip (i.e. calling that in a script will do the same as pressing the button with a mouse), so you can easily find out the calls for the actions which you want to automate. Alternatively, you can also search through the API documentation for blender python scripting here, which explains what these functions do in a bit more detail (or at least it does most of the time — some functions are just listed without explanation, presumably because no one’s had time to document them).
Then all you need are the objects you want to change to pass as arguments; those of the current scene live in bpy.context.scene.objects through which you could e.g. iterate using a for-loop in python or just access them by name like this: bpy.context.scene.objects["Cube"]
You can do something like this as shown in the script. However what is the name of the operator? If you head over to the scripting window, you can apply the operator once too see how is called in the info window, then you can copy directly this entry into the loop and change input arguments accordingly.
import bpy
# select all objects to be used as targets
# but select the source object last
# so is set as the active
selected_object = bpy.context.active_object
# this list of objects conists of all the selected objects
# but the source object (the active) is excluded
# (select from index 1 -- second position | up to last
other_objects = bpy.context.selected_objects[1:]
# and now loop all selected objects
for o in other_objects:
print('combine', selected_object.name, 'with', o.name)
o.location = selected_object.location
Wow thanks for sharing! That structure worked really well as a basis and after some tinkering I finally got it to work!! This is going to be a major time saver and a big boost on my workflow.
This is the script -
#Script for transferring weights from one object to multiple objects
#Select all your target objects first, then select the source last, and run the script
import bpy
source_mesh = bpy.context.active_object #variable for source
target_meshes = bpy.context.selected_objects[1:] #variable array for targets
for o in target_meshes:
bpy.ops.object.select_all(action='DESELECT') #deselecting everything
bpy.data.objects[o.name].select_set(True) #selecting target
bpy.data.objects[source_mesh.name].select_set(True) #selecting source
bpy.context.view_layer.objects.active = bpy.data.objects[o.name] #setting target as active
bpy.ops.paint.weight_paint_toggle() #entering Weight Paint mode
bpy.ops.object.data_transfer(use_reverse_transfer=True, data_type='VGROUP_WEIGHTS', layers_select_src='NAME', layers_select_dst='ALL') #transferring weights
bpy.ops.paint.weight_paint_toggle() #exit Weight Paint Mode
Cool, it seems that it worked fine. Just a quick question. I assume that this script can work fine if the meshes are identical clones, because vertex index is directly mapped to a weight index (eg: vertex at index 0 maps to weight index 0 etc).
So this means that if you get two different meshes from various sources you would have to find a good way to remap the vertices in the correct order.
Have you thought about this? Do you use it in the same way?
The transfer weights function inside of Blender is fantastic in this regard, I just wanted to be able to do it on multiple selected objects.
In conjunction with the Remesh tool in sculpt mode, this can be a very efficient technique to paint weights on characters or objects that are complex and made up of several parts