Skip to content
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Cannot retrieve contributors at this time
""" 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)