4

I have over 1000 animation files that I want to "crop" off keyframes outside of a specified range.

Keyframes all start at frame 1 instead of frame 0, as such I want to shift all keyframes by one frame such that the animations start at frame 0.

I have an int variable named "framelength" which stores the framenumber of the last good frame. I want to remove every keyframe after this value.

The most similar code I was able to find online was:

How to remove all only rotation keyframes from current action with Python? and Editing fcurve.keyframe points in FAST mode? Both were written by BatFINGER.

I tried using a combination of the two to achieve what I want, but am struggling with deleting only certain keyframes.

ob = context.object
ad = ob.animation_data
action = ad.action if ad else None
if action:
    for fc in action.fcurves:
        sel = list(bool(i > int(framelength)) for i in range(len(fc.keyframe_points)))
        for i in range(len(fc.keyframe_points)):
            if i>35:
                fc.pop()

Above is my attempt at solving the problem.

kriNon
  • 81
  • 3
  • 1
    Here's another that may be useful, creates a new sliced action. To make the default start frame 0 change to _kfs[:,0] -= start_frame. For when use shift is set. https://blender.stackexchange.com/a/214899/15543 – batFINGER May 08 '21 at 10:21

1 Answers1

4

I got it working thanks to batFINGER's comment.

My final code looked like this:

import numpy as np
def action_slice(action, start_frame, end_frame, shift=True): 
    copy = bpy.data.actions.new(action.name)
    copy.id_root = action.id_root
for fcurve in action.fcurves:
    kfs = np.empty(len(fcurve.keyframe_points) << 1)
    fcurve.keyframe_points.foreach_get("co", kfs)
    kfs = kfs.reshape((-1, 2))
    _fc = copy.fcurves.new(
            fcurve.data_path,
            index = fcurve.array_index
            )
    _fc.keyframe_points.add(0)
    _kfs = kfs[
            np.logical_and(
                kfs[:,0] >= start_frame, 
                kfs[:,0] <= end_frame
                )
            ]
    if shift:
        _kfs[:,0] -= start_frame
    _fc.keyframe_points.add(_kfs.shape[0])
    _fc.keyframe_points.foreach_set("co", _kfs.ravel())
return copy

def object_do_slice(string, endframe): ob = bpy.data.objects.get(string)#context.object ad = ob.animation_data action = ad.action if ad else None if action: ad.action = action_slice(action, 1, endframe, shift=True)

object_do_slice("Root",framelength+1)

kriNon
  • 81
  • 3