Skip to content

Commit a1e88cc

Browse files
committed
feat(entity): Rework duplicate method
closes DLR-RM#1012
1 parent f2e77c0 commit a1e88cc

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

blenderproc/python/types/EntityUtility.py

+26
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,32 @@ def deselect(self):
152152
""" Deselects the entity. """
153153
self.blender_obj.select_set(False)
154154

155+
def duplicate(self, duplicate_children: bool = True, linked: bool = False) -> "Entity":
156+
""" Duplicates the object.
157+
158+
:param duplicate_children: If True, also all children objects are recursively duplicated.
159+
:param linked: If True, object data is not copied.
160+
:return: A new mesh object, which is a duplicate of this object.
161+
"""
162+
new_entity = self.blender_obj.copy()
163+
if not linked and self.blender_obj.data is not None:
164+
new_entity.data = self.blender_obj.data.copy()
165+
bpy.context.collection.objects.link(new_entity)
166+
167+
duplicate_obj = convert_to_entity_subclass(new_entity)
168+
if type(duplicate_obj) != type(self):
169+
warnings.warn(f"Duplication is only partly supported for {type(self)}")
170+
171+
if duplicate_children:
172+
for child in self.get_children():
173+
duplicate_child = child.duplicate(duplicate_children=duplicate_children)
174+
duplicate_child.set_parent(duplicate_obj)
175+
176+
duplicate_child.blender_obj.matrix_basis = child.blender_obj.matrix_basis.copy()
177+
duplicate_child.blender_obj.matrix_parent_inverse = child.blender_obj.matrix_parent_inverse.copy()
178+
179+
return duplicate_obj
180+
155181
def clear_parent(self):
156182
""" Removes the object's parent and moves the object into the root level of the scene graph. """
157183
# Remember original object pose

blenderproc/python/types/MeshObjectUtility.py

-19
Original file line numberDiff line numberDiff line change
@@ -81,25 +81,6 @@ def replace_materials(self, material: bpy.types.Material):
8181
# add the new one
8282
self.add_material(material)
8383

84-
def duplicate(self, duplicate_children: bool = True) -> "MeshObject":
85-
""" Duplicates the object.
86-
87-
:param duplicate_children: If True, also all children objects are recursively duplicated.
88-
:return: A new mesh object, which is a duplicate of this object.
89-
"""
90-
new_entity = self.blender_obj.copy()
91-
new_entity.data = self.blender_obj.data.copy()
92-
bpy.context.collection.objects.link(new_entity)
93-
94-
duplicate_obj = MeshObject(new_entity)
95-
96-
if duplicate_children:
97-
for child in self.get_children():
98-
duplicate_child = child.duplicate(duplicate_children=duplicate_children)
99-
duplicate_child.set_parent(duplicate_obj)
100-
101-
return duplicate_obj
102-
10384
def get_mesh(self) -> bpy.types.Mesh:
10485
""" Returns the blender mesh of the object.
10586

tests/testEntity.py

+42
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,45 @@ def test_scene_graph_hierarchy_changes(self):
7474
self.assertTrue((grandchild.get_local2world_mat()[:3, 3] == [4, 0, 0]).all())
7575
self.assertEqual(root.get_children(), [grandchild])
7676
self.assertEqual(child.get_children(), [])
77+
78+
def test_duplicate_linked(self):
79+
bproc.clean_up(True)
80+
81+
cube = bproc.object.create_primitive("CUBE")
82+
duplicate_cube = cube.duplicate(False)
83+
self.assertEqual(cube.blender_obj.data, duplicate_cube.blender_obj.data)
84+
85+
empty = bproc.object.create_empty("empty")
86+
duplicate_empty = empty.duplicate(False)
87+
self.assertEqual(duplicate_empty.blender_obj.data, None)
88+
89+
light = Light()
90+
duplicate_light = light.duplicate(False)
91+
self.assertEqual(light.blender_obj.data, duplicate_light.blender_obj.data)
92+
93+
def test_duplicate_hierarchy(self):
94+
bproc.clean_up(True)
95+
96+
root = bproc.object.create_primitive("CUBE")
97+
child = bproc.object.create_primitive("CUBE")
98+
grandchild = bproc.object.create_primitive("CUBE")
99+
100+
grandchild.set_location([1, 1, 1])
101+
grandchild.set_parent(child)
102+
103+
child.set_location([1, 1, 1])
104+
child.set_parent(root)
105+
106+
duplicate_root = root.duplicate()
107+
duplicate_child = duplicate_root.get_children()[0]
108+
duplicate_grandchild = duplicate_child.get_children()[0]
109+
110+
# world location
111+
self.assertTrue((duplicate_root.get_local2world_mat()[:3, 3] == [0, 0, 0]).all())
112+
self.assertTrue((duplicate_child.get_local2world_mat()[:3, 3] == [1, 1, 1]).all())
113+
self.assertTrue((duplicate_grandchild.get_local2world_mat()[:3, 3] == [2, 2, 2]).all())
114+
115+
# relative location
116+
self.assertTrue((duplicate_root.get_location() == [0, 0, 0]).all())
117+
self.assertTrue((duplicate_child.get_location() == [1, 1, 1]).all())
118+
self.assertTrue((duplicate_grandchild.get_location() == [1, 1, 1]).all())

0 commit comments

Comments
 (0)