Hi! I made this script to clear the useless keyframes from objects of a physics simulation. It removes the keyframes on frames that have same position data. It works, but it is incredible slow! It is slower as the complexitiy of the scene increases, and in my scene I have 1700 simulated objects.
So I wanto to ask if there is a way to make it work faster.
Here’s the code. It works on selected objects. For every object it goes back and forth in the frames and checks objects position, and removes the keyframes when needed. Any idea to improve it?
import bpy, copy
start_frame = 2
end_frame = 2500
objects = bpy.context.selected_objects
bpy.ops.object.select_all(action = 'DESELECT')
for obj in objects:
obj.select = True
bpy.context.scene.objects.active = obj
for f in range(start_frame, end_frame):
bpy.context.scene.frame_set(f)
cur_loc = copy.copy(obj.location)
bpy.context.scene.frame_set(f+1)
next_loc = copy.copy(obj.location)
bpy.context.scene.frame_set(f-1)
prev_loc = copy.copy(obj.location)
if cur_loc == prev_loc and cur_loc == next_loc:
bpy.context.scene.frame_set(f)
bpy.ops.anim.keyframe_delete_v3d()
obj.select = False
In my simulation only the 10% of the keyframes are useful, so I suppose that removing those useless will make the file lighter and saves memory during the rendering process of the animation.
Isn’t it impossible to compare the float error variable with a difference between two vector3 variables?
Also, does this check also the difference between the current and the previous frame? I don’t want to delete a frame just becouse the next is equal. It must be equal also to the previous.
Anyway, I supposed that the frame changing is what slows down the script.
Don’t know if there’s such a function, that’s why I used the distance between the location in the previous keyframe, and the current one.
the script only deletes a keyframe, if is equal to the previous keyframe… this poses some problems when objects stop/resume movement.
it wouldn’t be difficult to improve it, and even remove keyframes during the movement’s if they are just interpolations of the previous and next keyframes.
There’s an excellent script Aaron Koressel wrote for Maya many years ago that does this exact function. I use it every day. It’s written in MEL, but it should be simple enough to translate into Python, since it’s mostly just Python functionality, not Maya commands. You can find it in two places: my github repo for my maya prefs and Aaron’s website.
Found this pretty high up on Google, but I must say that ChatGPT did a better job solving my problem, so I’ll post its solution here:
import bpy
def remove_redundant_keyframes(action, threshold=1e-6):
"""
Removes redundant keyframes from all F-Curves in the active action.
A keyframe is considered redundant if it has the same value as its neighbors within a given threshold.
"""
for fcurve in action.fcurves:
if not fcurve.keyframe_points:
continue
keyframes = fcurve.keyframe_points
i = 1 # Start from second keyframe
while i < len(keyframes) - 1:
prev_kf = keyframes[i - 1]
curr_kf = keyframes[i]
next_kf = keyframes[i + 1]
# Check if current keyframe is redundant (same value as before and after within threshold)
if (
abs(prev_kf.co.y - curr_kf.co.y) < threshold and
abs(next_kf.co.y - curr_kf.co.y) < threshold
):
keyframes.remove(curr_kf)
else:
i += 1 # Only increment if we didn't delete to avoid skipping elements
# Run the function
for i, action in enumerate(bpy.data.actions):
print(f"Cleaning {i}/{len(bpy.data.actions)}")
remove_redundant_keyframes(action)
Instead of comparing distances in 3D space across various frames, it just reads the fcurve keyframe point data and compares it against the previous frame, which is exactly what anyone finding this thread would want to do. This then also does rotation, scale, and any other properties, since fcurves are just fcurves.