Script to transfer weights from one mesh to multiple objects?

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.

Thanks a bunch if you’re willing to help!

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"]

2 Likes

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
2 Likes

Thanks for the tips! :slight_smile:

Wow thanks for sharing! That structure worked really well as a basis and after some tinkering I finally got it to work!! :grin: 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
1 Like

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).

vertex_weight_transfer

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?

1 Like

Well, if they had to be identical, that wouldn’t be very ideal. Fortunately, I tested it out on something crazy and it worked out pretty well

On the left is the source which is basically a cage mesh that fits around the target, which is a bunch of haphazardly arranged independent spheres.

Here’s what it looks like after transferring weights. As you can see, the spheres deform well in the volume of the cage

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

Just thought this might be useful resource - https://www.3dfiggins.com/Resources/

ILM animator Kiel Figgins described this “Sock Puppet” approach that he uses in Maya, and I wanted to recreate a similar workflow for Blender

Very intersting technique. :slight_smile:

1 Like