9
$\begingroup$

I know how to successfully duplicate an object by using

bpy.ops.object.add_named(name = 'TemplateObjectName')

If the template object named 'TemplateObjectName' has animations, particle systems and modifiers attached to it, the previous call will create a duplicate object that also has those components. However, if I duplicate an object using

template_object = bpy.data.objects['TemplateObjectName']
new_object = bpy.data.objects.new('NewObjectName', template_object.data)
collection.objects.link(new_object)

how do I attach the template object's animation, modifiers, particle systems...?

$\endgroup$

3 Answers 3

19
$\begingroup$

Make copies of ID data with ID.copy()

For blender data ID objects ie objects in bpy.data.objects meshes in bpy.data.meshes actions in bpy.data.actions the ID object has a copy method .

For a bpy.types.Object object copy, the copy will have the same transforms, parent, modifiers, constraints, animation data et all of the original. All linked data will be same as original. eg if mesh of original is bpy.data.meshes["Cube"] so is the copy's. Fortunately the mesh also has a copy method.

template_ob = bpy.data.objects.get("template")
if template_ob:
    ob = template_ob.copy()
    # link to collection if need be
    collection.objects.link(ob)

the copy ob has the same linked data as the original template_ob.data is ob.data is True.

    # assign a copy of the mesh to copy object
    ob.data = ob.data.copy()

Assuming we've checked original has an action then to make the action a copy of original's

    action = ob.animation_data.action
    # make it a copy
    ob.animation_data.action = action.copy()

To unassign

    #make it None (no action assigned)
    ob.animation_data.action = None

Or in one fell swoop, remove all animation data including actions and drivers

    ob.animation_data_clear()

Constraints and modifiers data are not linked. The copy has the same of each, including the same names, as original. The vertex groups and target objects pointed to will be same as original, and may need to be adjusted.

To remove all modifiers and constraints on copy

    ob.modifiers.clear()
    ob.constraints.clear()

Duplicate Object operator. bpy.ops.object.duplicate()

can also use the duplicate operator. As with operators they work on the context and selected objects, which if need be can be set within a script.

Alternatively with an override dictionary. Early testing and 2.8 appears much simpler on this front.

Test code (can confirm works as expected when run in python console on 2.8)

Duplicate an object template_ob with linked data

bpy.ops.object.duplicate(
        {"object" : template_ob,
         "selected_objects" : [template_ob]},
        linked=True)
ob = context.object # newly duped object

linked=False is the default.

Making a new object with copies of originals data.

From question:

template_object = bpy.data.objects['TemplateObjectName']
new_object = bpy.data.objects.new('NewObjectName', template_object.data)
collection.objects.link(new_object)

how do I attach the template object's animation, modifiers, particle systems...?

Strictly speaking this is not a duplicate. It is a new object that shares the originals data part. Or similarly in your answer where it shares data part, and original action or copy thereof. Results will match in the simplest of cases, ..and may be the answer you are seeking. However for others wishing to duplicate their objects in 2.8 using this method

Can they be assured that nothing is affected by not having a property of original on the new object?

  • The action or driver may refer to data paths of properties on original that either, will not be defined, or set to default on the new object.
  • Relations: modifiers constraints animations could require the original having a certain parent or transform.
  • How to go about copying over the constraints / modifiers of the original? What if they have drivers? Should target objects be duped,
  • Vertex groups? .

To reiterate, making a new object sharing some chosen DNA of the original is IMO not duplicating. Obviously there's no need to write a script with all the options required to emulate ob.copy() just like there's no need to use ob.copy() to add a new object with default settings, and only a few chosen attributes of ob

Putting the body of Porsche on your new car, and driving it like it's a Porsche, doesn't make it a Porsche, it may however achieve the result you are after

$\endgroup$
3
  • 2
    $\begingroup$ Thanks @batFINGER for your answers. They didn't just solve my problem, they also provided much needed general knowledge that I much in need of. $\endgroup$
    – Dazotaro
    Commented Apr 2, 2019 at 16:20
  • 1
    $\begingroup$ Thanks @p2or for your answers. They didn't just solve my problem, they also provided much needed general knowledge that I much in need of. $\endgroup$
    – Dazotaro
    Commented Apr 2, 2019 at 16:20
  • $\begingroup$ I have collection object is not define when running your code $\endgroup$
    – G M
    Commented Jan 21, 2022 at 15:27
2
$\begingroup$

Note that this is a complement of information for the already provided answers in case someone finds this post looking for a way to duplicate an object. Read the accepted answer to understand how one can do more than just duplicating an object.

cube = bpy.data.objects["Cube"]
cube_2 = bpy.data.objects.new('Cube 2', cube.data)
cube_2.location.y += 5
bpy.data.collections["Collection"].objects.link(cube_2)

Above is a simple example of the code needed in the default/generic template to duplicate the cube and have a new instance called cube_2 added to the default collection. I changed the location of the duplicate so we can see both cubes at once.

$\endgroup$
1
  • 1
    $\begingroup$ Only the mesh of original object properties will be duplicated. I imagine that cube 2's y location will be 5. Not always 5 from original. (Test on objects without identity transform). Other object properties like modifiers and constraints will not be on copy. (Appear to be answering question using code from question) $\endgroup$
    – batFINGER
    Commented May 14, 2020 at 8:59
0
$\begingroup$

This is how you can duplicate the object: linking the original object's mesh data, and with/without linking the original object's animation data:

template_object = bpy.data.objects.get('TemplateObjectName')
if template_object:
    # Create the new object by linking to the template's mesh data
    new_object = bpy.data.objects.new('NewObjectName', template_object.data)
    # Create a new animation for the newly created object
    animation = new_object.animation_data_create()

    # Option 1: Linking action
    #-------------------------
    #Assign the template object's action to the new animation
    animation.action = template_object.animation_data.action

    # Option2: NOT Linking action
    #----------------------------
    # Assign a copy of the template object's action to the new animation
    animation.action = template_object.animation_data.action.copy()
    # Rename it if desired
    animation.action.name = 'NewAction'

    # Link the new object to the appropriate collection
    collection.objects.link(new_object)
$\endgroup$

You must log in to answer this question.

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