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 reversed(fcu.keyframe_points.values()):
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 )