← All ideas
  • Published 16 Jul 2022

create driver driven by a new custom property

In this Blender StackExchange discussion we discuss a workflow of creating several Drivers that have new Custom Properties that allow for linked library overrides on modifier parameters. It is not a trivial task and there is a python script that would be nice to have in the RMB menu for modifier properties.

alt text

alt text

The python solution is partially represented by the following, but should be a RMB menu action when hovering over a property.


# ========================================================================
# Function declarations
# ========================================================================

def get_property_name(obj,data_path) -> str:
    s = data_path
    i = s.find('.')
    data_path_1 = ""
    data_path_2 = data_path
    if i > 0:
        ri = s.rindex('.')
        data_path_1 = '.' + s[0:ri]
        data_path_2 = s[ri+1:len(s)]
    data = eval("bpy.context.object" + data_path_1)
    print('get_property_name data=',data)
    return data.rna_type.properties[data_path_2].name if hasattr(data, data_path_2) else ''

def get_property_type(obj,data_path) -> type:
    print(obj,'....',data_path)
    #getattr(obj,data_path)
    return type(obj.path_resolve(data_path))

def clear_drivers(obj, data_path, index):
    if obj.animation_data is None:
        return
    drivers = obj.animation_data.drivers

    for d in drivers:
        if d.data_path != data_path:
            continue
        if index < 0:
            for idx in range(-1,3):
                obj.driver_remove(d.data_path, idx)
        else:
            obj.driver_remove(d.data_path, index)

def create_driver(fcurve, obj, custom_prop):
    d = fcurve.driver
    v = d.variables.new()
    v.name = "myvar"

    target = v.targets[0]
    target.id_type = 'OBJECT'
    target.id = obj
    target.data_path = '["' + custom_prop + '"]'
    d.expression = "myvar"
    print('create_driver for ',custom_prop)

# ========================================================================
# Initialize properties from first keying set
# ========================================================================
def keySetToDrivers():
    if(len(bpy.context.scene.keying_sets) == 0):
        print('First right click property and select "Add to Keying Set".')
        return
    ksPaths = bpy.context.scene.keying_sets[0].paths
    if(len(ksPaths)==0):
        print('First right click property and select "Add to Keying Set"')
        bpy.ops.anim.keying_set_remove()
        return

    for ks in ksPaths:   
        obj = bpy.data.objects[ks.id.name] # get the object for the custom props
        ks_use_entire_array = ks if ks.use_entire_array else False
        if(ks_use_entire_array):print('ks_use_entire_array for',ks.id.name)
        DATA_PATH = ks.data_path
        INDEX = -1 if ks_use_entire_array else ks.array_index

        CUSTOM_PROPERTY = get_property_name(obj,DATA_PATH)

        if ( CUSTOM_PROPERTY == '' ): continue # skip if error return

        print('DATA_PATH',DATA_PATH)

        if INDEX < 0:
            for idx in range(-1,3):
                custom_prop = CUSTOM_PROPERTY + ' [' + str(idx) + ']'
                if custom_prop in obj:
                    del obj[custom_prop]
        else:
            CUSTOM_PROPERTY = CUSTOM_PROPERTY + ' [' + str(INDEX) + ']'
            if CUSTOM_PROPERTY in obj:
                del obj[CUSTOM_PROPERTY]

        # ========================================================================
        # Add property and driver
        # ========================================================================

        if CUSTOM_PROPERTY in obj:
            print("WARNING: to prevent overwriting custom property, substituting with data_path name")
            continue

        clear_drivers(obj, DATA_PATH, INDEX)
        print('CUSTOM_PROPERTY',CUSTOM_PROPERTY)
        p = bpy.props.BoolProperty(name=CUSTOM_PROPERTY, default=0, options={'ANIMATABLE','LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'}, tags=set())
        initVal=0
        t=get_property_type(obj, DATA_PATH)
        print('get_property_type',t)
        if( t is type(bool())):
            print('type is bool (int)')
            initVal=0
        elif( t is type(int())):
            print('type is int')
            initVal=0
        elif( t is type(float())):
            print('type is float')
            initVal=0.0
        elif( t is type(str())):
            print('type is string')
            initVal=''

        obj[CUSTOM_PROPERTY] = initVal # you can add the custom property like this
        ui = obj.id_properties_ui(CUSTOM_PROPERTY)
        ui.update(description=DATA_PATH)
        if( t is type(bool())):
            print('type is bool')
            ui.update(default=0,min=0,max=1)
        elif( t is type(int())):
            print('type is int')
            ui.update(default=0,min=0)
        elif( t is type(float())):
            print('type is float')
            ui.update(default=0,min=0.0)
        elif( t is type(str())):
            print('type is string')
            #ui.update(default=0,min=0)
        #ui.update(default=0,min=0)
        obj.property_overridable_library_set('["'+CUSTOM_PROPERTY+'"]', True)

        fcurve_or_list = obj.driver_add(DATA_PATH, INDEX)

        if type(fcurve_or_list) is list:
            for fcurve in fcurve_or_list:
                create_driver(fcurve, obj, CUSTOM_PROPERTY)
        else:
            create_driver(fcurve_or_list, obj, CUSTOM_PROPERTY)

    bpy.ops.anim.keying_set_remove() # clean up

keySetToDrivers()
100%

Development Status: Open

Upvote 2 Downvote 0
jamestomk
16 Jul 2022

2 Comments

xenwildman

Powerprops addon has this ability.

1
Topeich

Override anything would be lovely... I miss it so much since Softimage days :)