Let's say you have a rigged character...

My first impressions and thoughts about the Driver Tools addon:

• maybe the GUI should pertain to the Tool shelf rather than to Properties, just a doubt.

• the interface should have some labels to specify that the first object is the current one, and the second the substitute.

• The first object slot could also be empty (pasted objects or other cases), currently the addon returns an error.

• a major point is that Drivers can also have variable of other types, such as Single Property, and in this case they can have targets of many types (key, object, armature, image, etc.) and relative IDs

• actually some error checks for the active object would be opportune.

dirty-stick, don’t take these as requests, I’m just trying to help.

Thank you again,
paolo

EDIT: I have just read your last post, I agree

I tried and modified ‘ob1 check’ to fit my need of filling an empty assignment, to me it works but I don’t know if it’s correct, or it can lead to some mismatching or errors.


. . .
    # ob1: check if Object
    if context.scene.DT.ob1 != '':
        ob1 = bpy.data.objects[context.scene.DT.ob1]
    else:
        ob1 = None

    # ob2: check if Object
. . .

paolo

I see.
Probably be best to remove the error checks for ob1 and ob2.
Then add the logic for if the DT.obs are ‘’ or not.
Same as your code I guess.

    # error check
    OK = True

    # replace driver targets
    if OK:

        ob1 = None
        ob2 = None

        if context.scene.DT.ob1 != '':
            ob1 = bpy.data.objects[context.scene.DT.ob1]
        if context.scene.DT.ob2 != '':
            ob2 = bpy.data.objects[context.scene.DT.ob2]

        for ad in AD_dir:
            for d in ad.drivers:
                for dv in d.driver.variables:
                    for t in dv.targets:
                        if t.id == ob1:
                            t.id = ob2

If I understand correctly the code, now it permits also object 2 to be None, but I think that is not advisable, it will only lead to unusable drivers, and I can’t see the need for the OK variable after that change.

paolo

Ye, thats correct.
Its and odd design issue, I dunno the best way to solve it.

Ive been trying to solve the other issues, so the code uses all drivers and id types.
Ill try post a [wip addon] thread in the addon section sometime.

I am sorry that my knowledge of python and blender API is really too little to be of any help, I have made myself some attempts to extend the functionality to all the cases, but I only got errors…:no:

This addon does its work for my needs, it has been and will be very useful in my workflow, so let me say thank you once again.

FYI, for my personal use, after your suggestions I have corrected it like that:


     # error check
    OK = True


   # ob1: check if Object
    ob1 = None
    if context.scene.DT.ob1 != '':
        ob1 = bpy.data.objects[context.scene.DT.ob1]


    # ob2: check if Object
    if context.scene.DT.ob2 == '':
        self.report({"ERROR"},"Object Two: Select an Object.")
        OK = False


    # replace driver targets
    if OK:
        ob2 = bpy.data.objects[context.scene.DT.ob2]

        for ad in AD_dir:
            for d in ad.drivers:
                for dv in d.driver.variables:
                    for t in dv.targets:
                        if t.id == ob1:
                            t.id = ob2

Of course I will be glad when you post your progresses, as I think that when it’s complete it will fill a gap into the current blender functionality.

Cheers,
paolo

Sorry, been away from internet connection for a few days. Looks like dirty-stick is working away on this…

Anyhow, for what it’s worth, here’s what I came up with:


import bpy

bl_info = {
    "name": "Change Shape Key Driver Targets",
    "author": "dirty-stick, revolt_randy",
    "version": (0, 0, 1),
    "blender": (2, 6, 9),
    "location": "3D View -> Tool Shelf",
    "description": "",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Rigging"}


class DriverTargetsPanel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_Driver_Targets"
    bl_label = "Change Shape Key Driver Targets"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS" 
       
    @classmethod
    def poll(self, context):
    # check for mesh selected
        return (bpy.context.active_object.type == "MESH")
    
    def draw(self, context):
        wm = bpy.context.window_manager
        layout = self.layout
        
        row = layout.row()
        row.prop(wm, "armature_old") 
        row = layout.row()
        row.prop(wm, "armature_new")        
        row = layout.row()
        row.operator("changetargets.op")


class ChangeTargetsOperator(bpy.types.Operator):
    bl_idname = "changetargets.op"
    bl_label = "Change Driver Targets"
    bl_description ="Change the armature that is used as targets for shape key drivers" 
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        
        if bpy.context.window_manager['armature_new'] not in bpy.data.armatures:
            self.report({"ERROR"}, "New Armature Invalid")
            return {"FINISHED"}
               
        for d in bpy.context.active_object.data.shape_keys.animation_data.drivers:
            for dv in d.driver.variables:
                for t in dv.targets:
                    if t.id.name == bpy.context.window_manager['armature_old']:
                        t.id = bpy.data.objects[bpy.context.window_manager['armature_new']]
                    else:
                        self.report({"ERROR"}, "Previous Armature Invalid")
                  
        return {"FINISHED"} 


bpy.types.WindowManager.armature_old = bpy.props.StringProperty(
    name='Previous Armature',
    description='Name of previous Armature used for shape key drivers',
    default = "")

bpy.types.WindowManager.armature_new = bpy.props.StringProperty(
    name='New Armature',
    description='Name of current Armature used for shape key drivers',
    default = "")    
    

def register():
    bpy.utils.register_class(DriverTargetsPanel)    
    bpy.utils.register_class(ChangeTargetsOperator)    
    

def unregister():
    bpy.utils.unregister_class(DriverTargetsPanel)      
    bpy.utils.unregister_class(ChangeTargetsOperator)
    
    
if __name__ == "__main__":
    register()  

Basic error checking to make sure the previous armature name and new armature name are valid, nothing more. Nothing more is needed as a simple tool to just update the name of the armature in all shape key drivers on a mesh. It’s in the tool shelf area in the UI, only active when a mesh is selected. Oh, and I tested it with 2.70, not tested with any newer version than that.

Thought about this tool quite a bit, and basically anything in blender can be driven, so a tool to re-target drivers for everything would be quite a major undertaking, I think. Not something I would want to take on just because I’m a nice guy.

Anyway, anyone is free to use that code without any credit given. I’m done with this project, I’ve better blender projects to play with…

Randy

Hi Randy,
thank you very much for your interest and for the code!

What i find really useful in your implementation is the ‘Undo’ functionality, which can avoid you to mess up the scene if you make a mistake.

About the putting the UI in the Tool shelf, while I think on one hand that’s the proper place (I would have done the same), on the other I find it more difficult to find because of Tabs, I’m not certain…

What I personally prefer in the dirty-stick’s implementation is the use of object lists, from where you can choose the armatures, instead of having to write the names yourself.
It’s coming to my mind that it could be even better if the lists was restricted to armatures only, given that this is the only case the addon is capable to handle.

As for all the other types of drivers, I fully agree that it would be a hard task to fulfill, unless there’s a way to access each single driver and query its type, but it seems to me that it’s not possible, moreover they can belong either to objects or to object.data and you have to look for them separately.

Cheers,
paolo

Ive found its not so hard to replace all drivers.
In bpy.context, .animation_data is only allocate in a few places, so you make list based on the scene, then iterate all drivers in the scene.
I was suprised how easy it was. :expressionless:

Hi dirty-stick,
thank you for informations, sadly my python sucks, so in my previous attempts I was not able to avoid errors, e.g. I can’t understand why the conditional statement “if bpy.context.active_object.animation_data” didn’t work.

Anyway I intend to try again.

paolo

EDIT: they are not so few after all, from the blender API documentation: