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座標だけをキーフレームにしていた場合とか、イージング処理によって若干異なるアニメーションになる可能性があるので注意が必要です。
コメント