Blender Python ボーンの親を変更する

やあ

いろんなキャラモデルを共通のアーマチュアで作ったけど、後からボーンの親を変更したいという状況が起こって、手動で全部書き換えるのはめんどうだなーって思って書いたよ。

注意

自分の環境ではこれで動きましたが、念のため、使用する際にはバックアップを取っておくことをお勧めします。
何か問題が起こっても僕の責任ではありません。

環境

Blender 2.90.0

コード

import bpy

target_armature_names = [
     "A", "B", "C"
]

reparents = [
    "Hand_R"
]

new_parent_name = "Wrist_R"

def get_object(name : str):
    return bpy.data.objects[name]

for target_armature_name in target_armature_names:    
    armature = get_object(target_armature_name)
    if armature is None:
        continue
    # アーマチュアを選択して編集モードにすることでedit_bonesからedit_boneを取得できる。
    armature.select_set(True)
    bpy.ops.object.mode_set(mode = "EDIT")
    new_parent = armature.data.edit_bones.get(new_parent_name)
    for reparent_target in reparents:
        target_edit_bone = armature.data.edit_bones.get(reparent_target)
        if target_edit_bone is None:
            continue
        target_edit_bone.parent = new_parent
    # 次に編集するアーマチュアを編集モードにできなくなるので、編集が終了したら、選択解除して、オブジェクトモードにしておく。
    armature.select_set(False) 
    bpy.ops.object.mode_set(mode = "OBJECT")

使い方

  1. target_armature_namesに編集したいアーマチュアの名前を詰め込む。

  2. reparentsにペアレントを編集したいボーンの名前を詰め込む。

  3. new_parent_nameに新しいペアレントの名前を設定する。

  4. スクリプトを走らせる。

ボーンごとに設定するペアレントを指定したい場合。

import bpy

target_armature_names = [
     "A", "B", "C"
]

reparents = [
    ("Hand_R", "Wrist_R"),
    ("Hand_L", "Wrist_L")
]

def get_object(name : str):
    return bpy.data.objects[name]

for target_armature_name in target_armature_names:    
    armature = get_object(target_armature_name)
    if armature is None:
        continue
    armature.select_set(True)
    bpy.ops.object.mode_set(mode = "EDIT")
    for reparent_target, new_parent_name in reparents:
        new_parent = armature.data.edit_bones.get(new_parent_name)
        target_edit_bone = armature.data.edit_bones.get(reparent_target)
        if target_edit_bone is None:
            continue
        target_edit_bone.parent = new_parent
    armature.select_set(False) 
    bpy.ops.object.mode_set(mode = "OBJECT")

こちらはテストしていないですが、これで問題なく動くはずです。