Is there a simple way in Python to move all keyframes in time in one go?

I’ve a complex scene with a load of traditional keyframed animations going on - much of it from a baked physics sim.

So I can do a nice smooth overcrank effect (ie smoothly slow time down, so we can see part of the action in super-slow-motion), I need to render out frames at sub-frame intervals.

Blender can certainly render out non-integer frames, as it does if you use the Time Remapping feature, but I need more fine-grained control. I need to be able to render the scene at, say, 3.2 frames in, 3.75 frames, 3.96 frames etc.

The only solution I can see, given that I can’t directly tell Blender to render the scene at 3.96 frames in, is to use Python to move all my keyframes back by 3.96 frames, then I can just render frame “0”. Repeat for each frame I need.

I can do it manually by going to the Dope Sheet, selecting all keyframes, switching off Frame Snapping, and dragging the whole lot in one go, but I need to do it with Python - I need about 200 frames rendering.

Question: What’s the simplest way to move every keyframe in a whole scene back/forward in time by a certain amount?

  • Do I have to iterate through every object, every animation, every track, every key?
  • Or would it be better to approach it more like a macro: have my script do the motions I’d perform in the Dope Sheet to do the same thing?

Any suggestions for the easiest approach?

If you want to change keyframes of all actions, you can do:


import bpy

for action in bpy.data.actions:
    for fcurve in action.fcurves:
        for point in fcurve.keyframe_points:
            point.co.x -= 3.96
1 Like

Wow, thanks CoDEmanX - that looks so much simpler than what I was expecting to have to do. I reckon it’ll do the trick!

Code needed adapting slightly - it didn’t move the keyframes’ bezier handles. Just for completeness, here’s the code I used:


    # theTime is the new frame time I need rendering (as a float) - obtained from a 
    # list of times cut and pasted from an After Effects Time Remapping track.
    # This chunk of code is executed for each frame:

    theOffset = theTime - prev_time
    prev_time = theTime
    
    # move everything to new position
    for action in bpy.data.actions:
        for fcurve in action.fcurves:
            for point in fcurve.keyframe_points:
                point.co.x -= theOffset
                # don't forget the keyframe's handles:
                point.handle_left.x -= theOffset
                point.handle_right.x -= theOffset
    
    # adjust the motion blur duration to half the interval between this and the last frame
    bpy.data.scenes["Scene"].render.motion_blur_shutter = (theOffset / 2)

    # insert your own render code here!

Thanks again, CoDEmanX - hugely helpful :slight_smile:

1 Like

I have question post in here, I just want move last keyframe, can anyone help me, thanks!: