blenderでオブジェクトの群にそれぞれにアニメーションを設定していて、途中からオブジェクトのアニメーションをそっくり入れ替えたくなることはありますよね! (ありました。)

Dope Sheet上でポチポチやるのはめんどいしミスりそうなのでもちろんPythonでやります:

objname1 = "cube_1"  # キーフレームを入れ替えたいオブジェクトの名前1
objname2 = "cube_2"  # キーフレームを入れ替えたいオブジェクトの名前2
keyframe_swap_start = 300  # これ以降のキーフレームを入れ替える
obj1 = bpy.data.objects[objname1]
obj2 = bpy.data.objects[objname2]
def get_keyframes(obj):
    keys_rot = {}
    keys_scale = {}
    keys_loc = {}
    fcurves = obj.animation_data.action.fcurves
    for fc in fcurves:
        if fc.data_path == "rotation_euler":
            keyframes = keys_rot
        elif fc.data_path == "scale":
            keyframes = keys_scale
        elif fc.data_path == "location":
            keyframes = keys_loc
        for kp in fc.keyframe_points:
            fr = str(int(kp.co[0]))
            if fr not in keyframes:
                keyframes[fr] = [0, 0, 0]
            keyframes[fr][fc.array_index] = kp.co[1]
    return keys_rot, keys_scale, keys_loc

# gather keyframes
keys_rot_1, keys_scale_1, keys_loc_1 = get_keyframes(obj1)
keys_rot_2, keys_scale_2, keys_loc_2 = get_keyframes(obj2)
# swap
def swap_keyframes(obj1, obj2, keys1, keys2, swap_start, fc_data_path):
    for fr, co in keys1.items():
        frame = int(fr)
        if frame < swap_start:
            if fc_data_path == "rotation_euler":
                obj1.rotation_euler = co
            elif fc_data_path == "scale":
                obj1.scale = co
            elif fc_data_path == "location":
                obj1.location = co
            obj1.keyframe_insert(fc_data_path, frame=frame)
    for fr, co in keys2.items():
        frame = int(fr)
        if frame < swap_start: if fc_data_path == "rotation_euler": obj2.rotation_euler = co elif fc_data_path == "scale": obj2.scale = co elif fc_data_path == "location": obj2.location = co obj2.keyframe_insert(fc_data_path, frame=frame) # swap for fr, co in keys1.items(): frame = int(fr) if frame >= swap_start:
            if fc_data_path == "rotation_euler":
                obj2.rotation_euler = co
            elif fc_data_path == "scale":
                obj2.scale = co
            elif fc_data_path == "location":
                obj2.location = co
            obj2.keyframe_insert(fc_data_path, frame=frame)
    for fr, co in keys2.items():
        frame = int(fr)
        if frame >= swap_start:
            if fc_data_path == "rotation_euler":
                obj1.rotation_euler = co
            elif fc_data_path == "scale":
                obj1.scale = co
            elif fc_data_path == "location":
                obj1.location = co
            obj1.keyframe_insert(fc_data_path, frame=frame)

obj1.animation_data_clear()
obj2.animation_data_clear()
swap_keyframes(obj1, obj2, keys_rot_1, keys_rot_2, keyframe_swap_start, "rotation_euler")
swap_keyframes(obj1, obj2, keys_scale_1, keys_scale_2, keyframe_swap_start, "scale")
swap_keyframes(obj1, obj2, keys_loc_1, keys_loc_2, keyframe_swap_start, "location")

ただこのやり方ではrotation_euler, scale, locationなどの全要素をキーフレームとしているので、x座標だけをキーフレームにしていた場合とか、イージング処理によって若干異なるアニメーションになる可能性があるので注意が必要です。

関連記事

自作PCにubuntuでdeep learning用の環境とかを整える

1755 MHz OCのRTX 2080 TiタワーPC(32GBメモリ)を28万円で作った話

Razer Bladeのバッテリーをaliexpressで買って交換した

MiSTEL BAROCCO MD650Lの持ち運びにはあのケースがぴったり

高層を拒否し、「ニュー オールドタウン」を選択したフランクフルトの市民参加型都市計画

echo spotでスマホを持ってない人とテレビ電話をする方法

コメント

コメントを返信する

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です