2
$\begingroup$

I am trying to do as the title suggests: remove all keyframes and animation data from all selected objects.

I am just starting out with Python and add-on development so this has proven to be a challenge for me. This is what I have sofar:

class CULT_ClearAnimData(Operator):
    bl_label = "Clear Animation Data"
    bl_idname = "object.clear_anim_data"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        selected_obj = bpy.context.selected_objects
        scene = bpy.context.scene

        for x in selected_obj:
            selected_obj[x].select_set(True)
            bpy.ops.anim.keyframe_clear_v3d()

        return {'FINISHED'}

Edit: Got this to work:

class CULT_ClearAnimData(Operator):
bl_label = "Clear Animation Data"
bl_idname = "object.clear_anim_data"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
    sel_objs = [obj for obj in bpy.context.selected_objects]
    #bpy.ops.object.select_all(action='DESELECT')
    for obj in sel_objs:
        bpy.ops.anim.keyframe_clear_v3d()

    return {'FINISHED'}

I am not sure if my solution is "proper" or safe, but it works. Any alternative ways would be helpful.

$\endgroup$
1
  • $\begingroup$ You can also do sel_obj = [*bpy.context.selected_objects] or sel_obj = list(bpy.context.selected_objects), or use a tuple to make it immutable, which IMO scans and acts a bit cleaner. Also, you're not actually passing obj to keyframe_clear_v3d(), so you're not actually using sel_objs or the loop— I think you only have to call keyframe_clear_v3d() once, and it already does all selected objects. $\endgroup$
    – Will Chen
    Mar 21 at 22:46
3
$\begingroup$

One fell swoop approach.

copying the script from Delete animation of object

Uses Object.animation_data_clear() to remove all animation data from all selected objects.

import bpy

context = bpy.context
for ob in context.selected_objects:
    ob.animation_data_clear()

this will orphan any action not associated with other objects, and they will be dealt with on file save / reload.

Otherwise

orphans = [a for a in bpy.data.actions if not a.users]
while orphans:
    bpy.data.actions.remove(orphans.pop())
$\endgroup$
2
$\begingroup$

I don't believe you have to deal with keyframes individually. It's also better sometimes to avoid bpy.ops calls, as they're slower and IMO sometimes more opaque.

Keyframes are associated to objects via actions, so as a basic example that should be similar to what you have:

for obj in objs:
    if obj.animation_data: #Check for presence of animation data.
        obj.animation_data.action = None

You may also want to get rid of all the NLA tracks, and all the drivers:

for obj in objs:
    if obj.animation_data and obj.animation_data.nla_tracks
        for nt in obj.animation_data.nla_tracks:
            obj.animation_data.nla_tracks.remove(nt)

for obj in objs:
    if obj.animation_data and obj.animation_data.drivers
        for dr in obj.animation_data.drivers:
            obj.animation_data.drivers.remove(dr)

(You probably want to combine the loops into one.)

$\endgroup$
3
  • $\begingroup$ Thank you so much! I just today started focusing on coding add-ons, so I have a lot to learn. This will help me greatly moving forward. $\endgroup$
    – Jay
    Mar 21 at 22:59
  • 1
    $\begingroup$ @Jay Yeah, honestly, so much of it is just about figuring out where the data you want to change lives in Python. You probably already know this, but in most cases (but not this one, I think) you can mouse over a field in the UI to see the relevant Python path to it. Also poke around in the console and use autocomplete to get lists of everything's Python attributes, and search the docs if you're not sure. $\endgroup$
    – Will Chen
    Mar 21 at 23:11
  • $\begingroup$ I will do exactly that! Thanks again. $\endgroup$
    – Jay
    Mar 22 at 0:32

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.