0
$\begingroup$

The Problem

My preferred method is animating with constant interpolation and inserting a keyframe for "Whole Character", especially on extreme/key poses.

After setting initial poses, I'd like to adjust the timing of the whole character without unhiding all the character's controls.

A solution I've found

In Dope Sheet filtering:

  • disable Only Show Selected
  • enable Show Hidden
  • select the group where the character is in.

This works but it's quite time-consuming with many characters. And if I forget and retime keyframes without the filtering trick, I'll have a messy dope sheet to work with.

Does anyone have another idea on how to retime hidden controls?

Thank you!

$\endgroup$

1 Answer 1

0
$\begingroup$

ChatGPT gave me a script that does what I needed!

The script sets up a handler that switches the collection filter every time you select a new object.

For anyone interested:

import bpy

def set_dopesheet_filter_to_collection():
    # Get the active object
    obj = bpy.context.active_object
    
    if obj:
        print(f"Active object: {obj.name}")
        # Find the collection the object is in
        for collection in bpy.data.collections:
            if obj.name in collection.objects:
                # Ensure the context is set to the Dope Sheet editor
                for area in bpy.context.screen.areas:
                    if area.type == 'DOPESHEET_EDITOR':
                        for space in area.spaces:
                            if space.type == 'DOPESHEET_EDITOR':
                                # Override the context to set the filter
                                override = {'area': area, 'space_data': space, 'region': area.regions[-1]}
                                with bpy.context.temp_override(**override):
                                    space.dopesheet.filter_collection = collection
                                    print(f"Dope Sheet filter set to collection: {collection.name}")
                                return
        print("Object not found in any collection")
    else:
        print("No active object selected")

def check_selection(scene):
    set_dopesheet_filter_to_collection()

# Register the handler
bpy.app.handlers.depsgraph_update_post.append(check_selection)

print("Handler registered")

Edit: I went a bit further and asked GPT to make scripts for activating and removing this functionality for AbraTools shelf (https://github.com/abrasic/abratools). It's a bit buggy sometimes but works fine most of the time :)

DopesheetFilterActiveCollectionHandler.py

class script_info:
    name = 'Dopesheet Filter Active Collection Handler'
    icon = 'FILTER'
    context = 'DOPESHEET_EDITOR'

def execute():
    import bpy

    def set_dopesheet_filter_to_collection():
        # Get the active object
        obj = bpy.context.active_object
        
        if obj:
            print(f"Active object: {obj.name}")
            # Find the collection the object is in
            for collection in bpy.data.collections:
                if obj.name in collection.objects:
                    # Ensure the context is set to the Dope Sheet editor
                    for area in bpy.context.screen.areas:
                        if area.type == 'DOPESHEET_EDITOR':
                            for space in area.spaces:
                                if space.type == 'DOPESHEET_EDITOR':
                                    # Set Show Only Selected off and Show Hidden on
                                    space.dopesheet.show_hidden = True
                                    space.dopesheet.show_only_selected = False
                                    space.dopesheet.show_only_errors = False
                                    print("Visibility set to Show Hidden in Dopesheet")
                                    # Override the context to set the filter
                                    override = {'area': area, 'space_data': space, 'region': area.regions[-1]}
                                    with bpy.context.temp_override(**override):
                                        space.dopesheet.filter_collection = collection
                                        print(f"Dope Sheet filter set to collection: {collection.name}")
                                    return
            print("Object not found in any collection")
        else:
            print("No active object selected")

    def check_selection(scene):
        set_dopesheet_filter_to_collection()

    # Check if the handler already exists
    if 'handler_ref' in bpy.app.driver_namespace and bpy.app.driver_namespace['handler_ref'] in bpy.app.handlers.depsgraph_update_post:
        print("Duplicate handler exists")
    else:
        # Store the handler reference in the driver namespace
        bpy.app.driver_namespace['handler_ref'] = check_selection

        # Register the handler
        bpy.app.handlers.depsgraph_update_post.append(bpy.app.driver_namespace['handler_ref'])

        # Set Visibility to Show Hidden
        # Ensure the context is set to the Dope Sheet editor
        for area in bpy.context.screen.areas:
            if area.type == 'DOPESHEET_EDITOR':
                for space in area.spaces:
                    if space.type == 'DOPESHEET_EDITOR':
                        # Override the context to set the properties
                        override = {'area': area, 'space_data': space, 'region': area.regions[-1]}
                        with bpy.context.temp_override(**override):
                            space.dopesheet.show_hidden = True
                            space.dopesheet.show_only_selected = False
                            space.dopesheet.show_only_errors = False
                            print("Visibility set to Show Hidden in Dopesheet")
                        return

    print("Handler registered")

DopesheetFilterActiveCollectionHandler_Remove.py

class script_info:
    name = 'Remove Dopesheet Filter Active Collection Handler'
    icon = 'FILTER'
    context = 'DOPESHEET_EDITOR'

def execute():
    import bpy

    # Function to remove the specific handler
    def remove_handler():
        handler_ref = bpy.app.driver_namespace.get('handler_ref')
        if handler_ref and handler_ref in bpy.app.handlers.depsgraph_update_post:
            bpy.app.handlers.depsgraph_update_post.remove(handler_ref)
            print("Handler removed")
        else:
            print("Handler not found")

        # Reset the Dope Sheet visibility settings
        for area in bpy.context.screen.areas:
            if area.type == 'DOPESHEET_EDITOR':
                for space in area.spaces:
                    if space.type == 'DOPESHEET_EDITOR':
                        # Override the context to set the properties
                        override = {'area': area, 'space_data': space, 'region': area.regions[-1]}
                        with bpy.context.temp_override(**override):
                            space.dopesheet.show_hidden = False
                            space.dopesheet.show_only_selected = True
                            space.dopesheet.show_only_errors = False
                            space.dopesheet.filter_collection = None
                            print("Dope Sheet visibility settings reset")

    # Call the function to remove the handler and reset settings
    remove_handler()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .