Blender Python: 1:1 Vertex Group and Skin Weight Transfer Between Meshes
10 May 26 (4mo ago)
In Blender, skin weights are stored directly inside vertex groups. Interestingly, vertex groups aren't exclusive to bone deformation weights unlike in Maya or Cinema 4D. For better or worse, this allows you to manipulate skin weights completely outside of a joint hierarchy.
For illustration: in Maya or Cinema 4D, if you have Mesh A bound to joints A, B, C, and D, and you delete those joints (or blow away the rig), you immediately lose the skin weights unless you cached them out to an external file first (like Deformer > Export Weights).
In Blender, even if you delete the entire armature, your skin weights still sit happily inside the vertex groups. If you want to dump them into an external file or format them with Python, nothing stops you. That decoupling creates some really interesting behaviors.
Anyway, this article isn't about that. LOL.
To transfer vertex weights natively in Blender without touching code, you can just hit Ctrl + L > Transfer Mesh Data > Vertex Groups. Or, if you are after a more complex transfer like projecting weights between meshes with unequal point counts, you add a Data Transfer modifier and bake the result.
The scripts below are designed for the 1:1 identical topology case. They give you a one-click Python transfer with built-in sanity checks to verify matching vertex counts across minor mesh revisions.
In Blender, selection order dictates hierarchy: the first item clicked is a standard selection, and the last item clicked becomes the Active Object (highlighted in lighter orange). By selecting the Source first and the Target second, the scripts automatically resolve driver vs. driven.
Method 1: The Direct Python Index Loop
This script wipes existing target groups, recreates the source group layout, and assigns identical weights to identical vertex indices. It's clean, easy to read, and great for verifying point-by-point logic.
import bpy
def transfer_vertex_groups_by_index():
selected = bpy.context.selected_objects
# 1. Selection validation: exactly two objects required
if len(selected) != 2:
print("[Error] Select exactly two objects: Source FIRST, Target SECOND.")
return
# 2. Determine Source (first selected) and Target (active/last selected)
target_obj = bpy.context.active_object
if not target_obj or target_obj not in selected:
print("[Error] No active object found. Ensure the target is selected last.")
return
source_obj = selected[0] if selected[1] == target_obj else selected[1]
# 3. Geometry type validation
if source_obj.type != 'MESH' or target_obj.type != 'MESH':
print("[Error] Both selected objects must be Mesh types.")
return
# 4. Topology match validation
source_verts = len(source_obj.data.vertices)
target_verts = len(target_obj.data.vertices)
if source_verts != target_verts:
print(f"[Error] Vertex count mismatch! Source: {source_verts} | Target: {target_verts}")
print("This method requires identical vertex counts and order.")
return
print(f"Transferring weights: '{source_obj.name}' -> '{target_obj.name}'...")
# 5. Reset target groups for a clean 1:1 copy
target_obj.vertex_groups.clear()
# Recreate empty groups matching source names
for vg in source_obj.vertex_groups:
target_obj.vertex_groups.new(name=vg.name)
# Cache target vertex group objects by name for fast dictionary lookup
target_vg_map = {vg.name: vg for vg in target_obj.vertex_groups}
# 6. Transfer vertex weights by index
for v in source_obj.data.vertices:
v_idx = v.index
for g in v.groups:
src_group_name = source_obj.vertex_groups[g.group].name
weight = g.weight
target_vg = target_vg_map.get(src_group_name)
if target_vg is not None:
target_vg.add([v_idx], weight, 'REPLACE')
print(f"[Success] Transferred {len(source_obj.vertex_groups)} groups across {target_verts} vertices!")
# Run execution
transfer_vertex_groups_by_index()
Method 2: The Fast C-Engine Transfer (Instant on Dense Meshes)
A critical performance note on Method 1: calling target_vg.add([v_idx], weight, 'REPLACE') point-by-point runs entirely inside Python space. On dense character meshes (e.g., 50,000+ vertices with 80+ bone deformation groups), this approach makes millions of individual Python-to-C API calls and can freeze Blender for 30 to 90 seconds.
If you are dealing with high-density production assets, you can run Blender's internal C-based data transfer operator directly through Python. It finishes in under 0.1 seconds on identical topology:
import bpy
def fast_native_weight_transfer():
selected = bpy.context.selected_objects
if len(selected) != 2:
print("[Error] Select Source FIRST, Target SECOND.")
return
target_obj = bpy.context.active_object
source_obj = selected[0] if selected[1] == target_obj else selected[1]
if source_obj.type != 'MESH' or target_obj.type != 'MESH':
print("[Error] Both objects must be meshes.")
return
# Check vertex counts
source_verts = len(source_obj.data.vertices)
target_verts = len(target_obj.data.vertices)
if source_verts != target_verts:
print(f"[Error] Vertex count mismatch! Source: {source_verts} | Target: {target_verts}")
return
# Clear old target groups
target_obj.vertex_groups.clear()
# Create temporary Data Transfer modifier to utilize native C performance
dt_mod = target_obj.modifiers.new(name="TempWeightTransfer", type='DATA_TRANSFER')
dt_mod.object = source_obj
dt_mod.use_vert_data = True
dt_mod.data_types_verts = {'VGROUP_WEIGHTS'}
# 1:1 matching topology mapping
dt_mod.vert_mapping = 'TOPOLOGY'
# Generate layout and bake weights natively
bpy.ops.object.datalayout_transfer(modifier=dt_mod.name)
bpy.ops.object.modifier_apply(modifier=dt_mod.name)
print(f"[Success] Fast transfer complete from '{source_obj.name}' to '{target_obj.name}'.")
fast_native_weight_transfer()
Quick Step-by-Step Usage
- Open Blender and switch to the Scripting workspace.
- Click New in the Text Editor and paste either script.
- In the 3D Viewport (Object Mode):
- Click your Source mesh (the driver with painted weights).
- Hold Shift and click your Target mesh (the driven). The target must be the lighter orange active object.
- Press Alt + P (or click Run Script).
- Open the System Console (
Window > Toggle System Consoleon Windows) to verify the log output and confirm parity.