diff --git a/blender_ops.py b/blender_ops.py index a768a1e..b75cbdf 100644 --- a/blender_ops.py +++ b/blender_ops.py @@ -332,11 +332,26 @@ elif OP == 'graft': raise SystemExit(f'part rig shares {len(clash)} bone name(s) with the body ' f'({sorted(clash)[:3]}…). Joining would silently repoint weights — ' f'use --bind=body instead.') + # join() deletes the part's armature OBJECT. Measured consequence: the part mesh's + # ARMATURE modifier is left pointing at None and the mesh gets re-parented to whatever + # empty sat above it (Sketchfab exports nest one), so it collapses from the wrist back to + # rest position at the origin. Save the placement and re-bind explicitly afterwards. + placed = {g.name: g.matrix_world.copy() for g in part_meshes} bpy.ops.object.select_all(action='DESELECT') parm.select_set(True); arm.select_set(True) bpy.context.view_layer.objects.active = arm # active survives the join bpy.ops.object.join() bpy.context.view_layer.update() + for name, wm in placed.items(): + g = bpy.data.objects.get(name) + if not g: + continue + for m in g.modifiers: + if m.type == 'ARMATURE' and m.object is None: + m.object = arm # re-bind the dangling modifier + g.parent = arm + g.matrix_world = wm # restore the placement join destroyed + bpy.context.view_layer.update() bpy.context.view_layer.objects.active = arm bpy.ops.object.mode_set(mode='EDIT') eb = arm.data.edit_bones