3
$\begingroup$

I am trying to build up a scene using python to copy objects and their drivers. The object to copy is a simple cube which has the Custom Property prop and a driver for its x-location. The driver consists of a Scripted Expression which references to the variable var, which is just the Single Property prop of the cube. So when I change the value of the Custom Property prop of the cube, I change its x-location.

To copy this cube, I wrote the following python script:

import bpy

def main():
    scn = bpy.context.scene
    cube = bpy.data.scenes['Scene'].objects['Cube']
    copy_loc_x = 2
    copy_obj(scn, cube, copy_loc_x)

def copy_obj(scn, obj, prop):
    # copy object and set a custom property
    copy = obj.copy()
    copy.data = obj.data.copy()
    copy['prop'] = prop
    scn.objects.link(copy)

if __name__ == '__main__':
    main()

This works perfectly to copy the object and set a new property for the copy, but the copy remains at the same x-location as the original cube. The reason for this is that the variable var of the copy still references to the Custom Property prop of the original cube.

How do I copy the cube, so that its driver variable is automatically referenced to its own Custom Property, just as Shift-D would do? Or, if this is not possible, how do I set the ID-block of a driver variable using python?

$\endgroup$
1
$\begingroup$

Assuming you only have one driver, and that one driver has only one variable, you can do this. after copying the object data:

copy.animation_data.drivers[0].driver.variables[0].targets[0].id = copy

If you have additional drivers and / or variables, you'll need to find better logic to access these. If you can upload a blend file, it will be easier to tell what the best method is.

$\endgroup$
1
$\begingroup$

Here is a retarget method from my sound drivers addon. It will change all targets that have target.id == from_target to to_target, for all drivers on the obj.

def retarget_driver(obj, from_target, to_target):    
    if hasattr(obj, "animation_data") and obj.animation_data is not None:
        #print("CHECKING OBJ", obj.name)
        targets = [t for d in obj.animation_data.drivers
                   for v in d.driver.variables
                   for t in v.targets
                   if t.id == from_target]

        for t in targets:
            t.id = to_target

Call below will change all obj targets to copy on the copy.

retarget_driver(copy, obj, copy)
$\endgroup$
1
$\begingroup$

If you want to copy the methodology of what Shift+D does, use the Duplicate Operator on the selected object(s) in Object Mode:

bpy.ops.object.duplicate()

By default this will create an identical copy, like pressing Shift+D in 3d View. By passing linked=True to the operator, you can also create a linked duplicate like pressing Alt+D on the keyboard. This will create a new object with all of its data (like the mesh) linked to the original object.

$\endgroup$

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.