5

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?

p2or
  • 15,860
  • 10
  • 83
  • 143
  • related: http://blender.stackexchange.com/questions/31348/duplicating-non-primitive-mesh-with-python – p2or Jun 24 '16 at 14:51

3 Answers3

3

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)
p2or
  • 15,860
  • 10
  • 83
  • 143
batFINGER
  • 84,216
  • 10
  • 108
  • 233
1

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.

TLousky
  • 16,043
  • 1
  • 40
  • 72
1

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.

p2or
  • 15,860
  • 10
  • 83
  • 143
Rick Riggs
  • 4,623
  • 14
  • 30