0
$\begingroup$

I'm trying to delete a specific keyframe at a specific frame in an animation action, I've tried both fcurve.keyframe_points.remove(keyframe) and fcurve.keyframe_delete(data_path, f= frame) with no luck.

Here's what I'm attempting to do, cropping an action keyframes between two given frame numbers:

def crop_animation(action, frame_start, frame_end):
    """ Crop the given action keyframes by removing all keyframes before 
    frame_start and after frame_end
    """
    fcurves = action.fcurves
    for fcu in fcurves:
        for i, key_frame in enumerate(fcu.keyframe_points):
            if i < frame_start or i > frame_end:
                fcu.keyframe_points.remove(key_frame)

and I get this error:

RuntimeError: Error: Keyframe not in F-Curve

and when I use fcurve.keyframe_delete(data_path, f= frame) instead:

def crop_animation(action, frame_start, frame_end):
    """ Crop the given action keyframes by removing all keyframes before 
    frame_start and after frame_end
    """
    fcurves = action.fcurves
    for fcu in fcurves:
        datapath = fcu.data_path
        for i, key_frame in enumerate(fcu.keyframe_points):
            if i < frame_start or i > frame_end:
                fcu.keyframe_delete(datapath, frame= i)

I get this error message:

TypeError: bpy_struct.keyframe_insert() property "pose.bones["Bone"].location" not found
$\endgroup$
1
$\begingroup$

The keyframes are not enumerated to frame.

Commented on another question of yours that there is no necessity that the keyframes fall exactly on integer values. Feel some of this answer could be there or vice versa

For the 2D keyframe point coordinate vector x is the frame, and y is the value y . Both are floats.

Eg a simple fcurve may have points (1, 30), (33, 23.0), (222.3, 0) having a frame range of 1 to 222.3 but an enumeration of 0, 1, 2.

To crop based on the frame of the keyframe point

import bpy

def crop_animation(action, frame_start, frame_end):
    """ Crop the given action keyframes by removing all keyframes before 
    frame_start and after frame_end
    """
    fcurves = action.fcurves
    for fcu in fcurves:
        for kf in fcu.keyframe_points:
            if kf.co.x < frame_start or kf.co.x > frame_end:
                fcu.keyframe_points.remove(kf)

# test call                
crop_animation(bpy.data.actions[0], 10000, 0)

Not sure how you get the keyframe not in fcurve error using code in question. .

Keyframe delete.

keyframe_delete is the opposite to keyframe_insert. An fcurve holds our keyframes, it is not itself keyframed.

For example if a location keyframe is added to context object on current frame then

>>> C.object.keyframe_insert('location')
True

>>> C.object.keyframe_delete('location')
True

removes it. Or in the case of bones

C.object.pose.bones["Foo"].keyframe_delete("location", frame=frame)

Make an amended copy of the action.

Have added a related link below re copying and cropping fcurves. To make your fcurve such that the kf's fall on integer frames would make a copy, then over it's integer range. For example if fc is our original, then the points of our new curve could be

[(frame, fc.evaluate(frame) for frame in range(frame_start, frame_end)] 

For bvh animation as displayed in other question with constant spacing between keyframes Another option is to scale the animation such that between frame distance is 1.

Related.

How to change an FCurve value in Python

Copying specific frames from one action to another ( python )

Python. How to find a point on the timeline where Fcurve reaches a certain value without changing current subframe?

$\endgroup$
2
  • $\begingroup$ This question was a bit irrelevant to the other one I had posted earlier because I used a different simple action for testing it other than the motion capture animation. The keyframes were equally distributed along integer frame numbers in this file, the keyframe delete in both cases is frame agnostic anyway so it should still be deleted regardless, yet it didn't work. and your code still gives me the error "RuntimeError: Error: Keyframe not in F-Curve". $\endgroup$
    – Ahmed Ali
    Jun 13 at 12:22
  • $\begingroup$ I preferred to remove keyframes rather than copy and evaluate the keyframes span I'm after because in my use case the keyframes I tend to remove are much less than the ones I need to keep, so I thought it might work faster, but now I think it might be a cleaner way to start fresh and evaluate since in your linked answer you are using numpy for doing the heavy lifting. So thank you ;) $\endgroup$
    – Ahmed Ali
    Jun 13 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.