# Splitting giant action into many sub actions via python?

I am currently working on integrating some assets into a custom engine. The engine relies on each animation being a separate action. The asset files I am working with however have all 50 animations "baked" into one singe "DefaultAction". I have resolved this issue in the past by simply copying the giant "DefaultAction" for every animation and removing the frames for the other animations. This however is rather tedious and time consuming.

I was wondering if the python api provided by blender contains the functionality required to be able to automate this task? For example, could I select the "DefaultAction" and then create multiple other actions based on the frames inside of "DefaultAction"?

Not looking for anyone to write this, just looking for confirmation that it is theoretically possible, and if so maybe a link to the classes of the api that could be used to do this. If it's doable I will see what I can put together and provide source for others as I believe this would be a valuable asset to have (since this isn't the first time I've run into this issue I suppose others have as well).

EDIT 2

I have given this a shot and think I'm close, but am having dificulty finding the right method/procedure to use to actually remove the keyframe_point from the fcurve of the action:

import bpy

base_action_name = "bend"

sub_actions = [
("sub_bend_001", 0, 14)
,("sub_bend_002", 15, 29)
]

for a in sub_actions:
new_action = bpy.data.actions.get(base_action_name).copy()
new_action.name = a[0]
for fc in new_action.fcurves:
i = 0
for kfp in fc.keyframe_points:
if i < a[1] or i > a[2]:
kfp.remove(kfp) # AttributeError: 'Keyframe' object has no attribute 'remove'
i = i + 1


Anyone know how to remove keyframe_points from an fcurve?

• Yes, definitely. Though it doesn't cover what you need, some basic keyframe access is here, here, the docs – Leander Apr 24 '20 at 18:15
• @Leander Thanks for the links, they helped. I have added some code to my question above. I think I've got it to where it needs to be, minus the removal of the keyframe_points from the fcurves. Would you happen to know how this is done? – nullReference Apr 24 '20 at 20:41
• @Leander using this method on the Keyframes stored within keyframe_points issues the following: AttributeError: 'Keyframe' object has no attribute 'remove'. I'm also still on 2.79. – nullReference Apr 24 '20 at 21:08
• @Leander Greatly appreciated! I'm going to keep at it for a bit longer. Feel like I'm really close. Will post back if I solve it. – nullReference Apr 24 '20 at 21:15

Got it! I was attempting to call the remove() method on a Keyframe object instead of the keyframe_points property of the FCurve. Below is working code that transforms a giant action into multiple sub-actions (working in 2.79, I'd say it should work in 2.8 as well but I don't know how extensive the changes were to the api between 2.79 and 2.8 so if you're on 2.8 your mileage may vary):

import bpy

# Define the name of the giant action containing all other sub-actions
base_action_name = "bend"

# Define the name, start, and end frame of each sub animation
sub_actions = [
("sub_bend_001", 0, 14)
,("sub_bend_002", 15, 29)
]

for a in sub_actions:
new_action = bpy.data.actions.get(base_action_name).copy()
new_action.name = a[0]
for fc in new_action.fcurves:
# Remove unwanted frames
for i in reversed(range(0, len(fc.keyframe_points))):
kfp = fc.keyframe_points[i]
frame_number = int(kfp.co[0])
if frame_number < a[1] or frame_number > a[2]:
fc.keyframe_points.remove(kfp)
# Shift remaining frames
offset = fc.keyframe_points[0].co[0]
for kfp in fc.keyframe_points:
kfp.co[0] = kfp.co[0] - offset
kfp.handle_left[0] = kfp.handle_left[0] - offset
kfp.handle_right[0] = kfp.handle_right[0] - offset