Skip to content

Commit

Permalink
Merge pull request #1013 from AndreyYashkin/duplicate_rework
Browse files Browse the repository at this point in the history
feat(entity): Rework duplicate method
  • Loading branch information
cornerfarmer authored Dec 12, 2023
2 parents 7b2daf7 + f89d844 commit 777be65
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 19 deletions.
26 changes: 26 additions & 0 deletions blenderproc/python/types/EntityUtility.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,32 @@ def deselect(self):
""" Deselects the entity. """
self.blender_obj.select_set(False)

def duplicate(self, duplicate_children: bool = True, linked: bool = False) -> "Entity":
""" Duplicates the object.
:param duplicate_children: If True, also all children objects are recursively duplicated.
:param linked: If True, object data is not copied.
:return: A new mesh object, which is a duplicate of this object.
"""
new_entity = self.blender_obj.copy()
if not linked and self.blender_obj.data is not None:
new_entity.data = self.blender_obj.data.copy()
bpy.context.collection.objects.link(new_entity)

duplicate_obj = convert_to_entity_subclass(new_entity)
if type(duplicate_obj) != type(self):
warnings.warn(f"Duplication is only partly supported for {type(self)}")

if duplicate_children:
for child in self.get_children():
duplicate_child = child.duplicate(duplicate_children=duplicate_children)
duplicate_child.set_parent(duplicate_obj)

duplicate_child.blender_obj.matrix_basis = child.blender_obj.matrix_basis.copy()
duplicate_child.blender_obj.matrix_parent_inverse = child.blender_obj.matrix_parent_inverse.copy()

return duplicate_obj

def clear_parent(self):
""" Removes the object's parent and moves the object into the root level of the scene graph. """
# Remember original object pose
Expand Down
19 changes: 0 additions & 19 deletions blenderproc/python/types/MeshObjectUtility.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,6 @@ def replace_materials(self, material: bpy.types.Material):
# add the new one
self.add_material(material)

def duplicate(self, duplicate_children: bool = True) -> "MeshObject":
""" Duplicates the object.
:param duplicate_children: If True, also all children objects are recursively duplicated.
:return: A new mesh object, which is a duplicate of this object.
"""
new_entity = self.blender_obj.copy()
new_entity.data = self.blender_obj.data.copy()
bpy.context.collection.objects.link(new_entity)

duplicate_obj = MeshObject(new_entity)

if duplicate_children:
for child in self.get_children():
duplicate_child = child.duplicate(duplicate_children=duplicate_children)
duplicate_child.set_parent(duplicate_obj)

return duplicate_obj

def get_mesh(self) -> bpy.types.Mesh:
""" Returns the blender mesh of the object.
Expand Down
42 changes: 42 additions & 0 deletions tests/testEntity.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,45 @@ def test_scene_graph_hierarchy_changes(self):
self.assertTrue((grandchild.get_local2world_mat()[:3, 3] == [4, 0, 0]).all())
self.assertEqual(root.get_children(), [grandchild])
self.assertEqual(child.get_children(), [])

def test_duplicate_linked(self):
bproc.clean_up(True)

cube = bproc.object.create_primitive("CUBE")
duplicate_cube = cube.duplicate(linked=True)
self.assertEqual(cube.blender_obj.data, duplicate_cube.blender_obj.data)

empty = bproc.object.create_empty("empty")
duplicate_empty = empty.duplicate(linked=True)
self.assertEqual(duplicate_empty.blender_obj.data, None)

light = Light()
duplicate_light = light.duplicate(linked=True)
self.assertEqual(light.blender_obj.data, duplicate_light.blender_obj.data)

def test_duplicate_hierarchy(self):
bproc.clean_up(True)

root = bproc.object.create_primitive("CUBE")
child = bproc.object.create_primitive("CUBE")
grandchild = bproc.object.create_primitive("CUBE")

grandchild.set_location([1, 1, 1])
grandchild.set_parent(child)

child.set_location([1, 1, 1])
child.set_parent(root)

duplicate_root = root.duplicate()
duplicate_child = duplicate_root.get_children()[0]
duplicate_grandchild = duplicate_child.get_children()[0]

# world location
self.assertTrue((duplicate_root.get_local2world_mat()[:3, 3] == [0, 0, 0]).all())
self.assertTrue((duplicate_child.get_local2world_mat()[:3, 3] == [1, 1, 1]).all())
self.assertTrue((duplicate_grandchild.get_local2world_mat()[:3, 3] == [2, 2, 2]).all())

# relative location
self.assertTrue((duplicate_root.get_location() == [0, 0, 0]).all())
self.assertTrue((duplicate_child.get_location() == [1, 1, 1]).all())
self.assertTrue((duplicate_grandchild.get_location() == [1, 1, 1]).all())

0 comments on commit 777be65

Please sign in to comment.