Hello,
I’m trying to duplicate selected object with it hierarchy without pre selecting objects inside.
What I have:
import bpy
# Set the area to the outliner
area = bpy.context.area
old_type = area.type
area.type = 'OUTLINER'
# Selecting Children and Parent objects
myObj = bpy.context.active_object
bpy.ops.object.select_grouped(type='CHILDREN_RECURSIVE')
myObj.select_set(True)
# Outliner Copy/Paste
bpy.ops.outliner.id_copy()
bpy.ops.outliner.id_paste()
# Selecting Pasted Objects (Make them active)
selection_names = [obj.name for obj in bpy.context.selected_objects]
for o in selection_names:
obj = bpy.context.scene.objects.get(o)
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
# Reset the area
area.type = old_type
The problem is that I cant get id_copy/paste work with hierarchy, it only duplicate selected object.
Sorry if it obvious, I have very low skill in python.
The outliner selection is not exposed to the python API. You can access collections and iterate over the objects in a collection and copy those objects, rather than using the id_copy() and id_paste() operators.
import bpy
collection_src = "Collection"
collection_dst = "Collection"
collection = bpy.data.collections[collection_src]
# If source and destination are the same iterating needs a copy
# of the input list using list() to prevent an infinite loop
for ob in list(collection.objects):
copy = ob.copy()
# Also copy mesh data (remove for linked mesh data)
copy.data = ob.data.copy()
# Link to destination collection
bpy.data.collections[collection_dst].objects.link(copy)
You can get the active collection with bpy.context.collection
Doing this recursively can be more complicated depending on how you want to handle collections and objects that are linked in the subtree multiple times. Here is a simple example that doesn’t prevent duplicating an object more than once. It will copy each object in the active collection recursively.
import bpy
def duplicate_children(collection, dst=None):
collection_dst = dst
if not collection_dst:
collection_dst = collection
for ob in list(collection.objects):
copy = ob.copy()
copy.data = ob.data.copy()
collection_dst.objects.link(copy)
for child in collection.children:
duplicate_children(child, dst)
collection = bpy.context.collection
duplicate_children(collection)
# Also can specify destination collection
duplicate_children(collection, bpy.data.collections['copies'])
The bpy.ops.object.duplicate() operator will work, but note that operators have more overhead so that will take more time to execute for large numbers of objects.