Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
128 lines (99 sloc) 4.5 KB
""" Shift keyframes in order to speed-up/slow-down a movie
or give time for another sequence of animations in between.
# Kristin Riebe, E-Science at AIP,, 04.02.2015
# NOTE: This can break your animation completely, if keyframes
# 'overtake' one another. There's no error handling included here.
# NOTE: Only works properly for fcurves with bezier-shape or poly-curves.
# Fcurve-modifiers are not taken into account.
# TODO: Maybe only stretch keyframes with data_path location etc.
# for material/texture fades, keep the distance, but
# shift the initial keyframe?
import bpy
import fnmatch
def get_actions_for_objects(namepattern="*"):
"""Collect all actions for the matching objects, their data
and their materials. Each material-action is to be used only once.
Return set of actions that can be used as input for
Keyword arguments:
namepattern -- name pattern of objects for which the animation-
actions are collected. (default: *)
# NOTE: If a non-matching object has the same material as a
# matching object, its material keyframes will be shifted!!
# If you don't want that, make the non-matching object's material
# unique beforehand.
# Find matching objects and store in list
objects = [obj for obj in
if fnmatch.fnmatchcase(, namepattern)]
# Gather all necessary actions for the objects and their materials,
# use set() in order to get unique values only,
# i.e. each animation-action (especially for materials) shall occur only
# once.
actions = set()
for obj in objects:
print("Object ",
if obj.animation_data is not None:
action = obj.animation_data.action
if action is not None:
if is not None:
if is not None:
action =
if action is not None:
# Loop over materials of this object
for matslot in obj.material_slots:
print("Material ",
if matslot.material.animation_data is not None:
action = matslot.material.animation_data.action
if action is not None:
return actions
def shift_keyframes(, factor=1, frameshift=0,
frame_start=0, frame_end=1000000):
Shift keyframes by given factor or frameshift for given actions
within given number of frames.
In details: shift the keyframe_points and their handles.
Only works properly for fcurves with bezier-shape or poly-curves.
Fcurve-modifiers are not taken into account.
Keyword arguments:
actions -- set or list of actions for which frames shall be
shifted (default: all actions available)
frame_start, frame_end -- range of frames for which keyframe_points
are shifted
factor -- stretch keyframe_points in given range by this factor
frameshift -- add this number to the keyframe_points in given range
# Loop over all actions and their fcurves,
# multiply keyframe-positions and handles by given factor
# and then shift by given frameshift
for action in actions:
print("Action ",
for fcu in action.fcurves:
print(" %s channel %d" % (fcu.data_path, fcu.array_index))
for keyframe in fcu.keyframe_points:
if ([0] >= frame_start
and[0] <= frame_end):
#print(" %s" % # coordinates x,y[0] =[0]*factor + frameshift
keyframe.handle_left[0] = (keyframe.handle_left[0]*factor
+ frameshift)
keyframe.handle_right[0] = (keyframe.handle_right[0]*factor
+ frameshift)
if __name__ == "__main__":
# Just stretch everything by factor 3
# Get actions for specified objects only
actions = get_actions_for_objects(namepattern='C*')
#print('Actions: ', actions)
# Stretch only keyframes for these animation actions
shift_keyframes(actions=actions, factor=2)