# Cleaning unwanted overlapping duplicate meshes

I have a model with hundreds of mesh objects. Unfortunately I clicked shift+D to duplicate many and did not notice. Later after working a while, I was rendering, and noticed there are double meshes overlapping each other.

How can I find all duplicate meshes and delete them. I could do it manually, just clicking, but it would take a long time and if I miss something i will not notice.

Is there any option, or can anybody suggest to me, how can I find all duplicate mesh and delete them.

Model with all double (duplicate) mesh

Final Result

• I have not written any Python for Blender for a while, but it should be relatively easy to loop through each object in turn and output the number of vertices stopping when the number matches the mesh you are trying to locate, or just listing them. – rob Aug 8 '17 at 7:45
• @rob any solution to find and delete all my duplicate mesh – atek Aug 8 '17 at 7:47
• – rob Aug 8 '17 at 8:14
• @rob i did not get what u mean. Is that about mesh calculation. I need my all double mesh to be search and highlight so that i can delete it. Do to the double mesh my file is heavy. so quick way to find and delete i needed. Thanks for the link – atek Aug 8 '17 at 8:19

Following a BIG CLUE given by @rob I've slapped together a script.

Give each mesh object in selection a key faces_edges_verts, for instance the default cube would have a key "6_12_8", 6 faces, 12 edges, 8 verts. Then check whether the coordinates of global bounding box, of any other objects that have same counts, match.

If they do select those objects to mark them as possible dupes.

To run suggest: Select all in scene, run script from text editor, and see if those objects that remain selected are dupes.... or close enough to... and then if all good hit x

import bpy
from mathutils import Vector
context = bpy.context

scene = context.scene
TOL = 1.0e-4 # reduced tolerance.

# routine to text matches on bound box.
def test(ob1, ob2):
# test if ob1 and ob2 which have same face/edge/vert count are same
bbox1 = [ob1.matrix_world * Vector(b) for b in ob1.bound_box]
bbox2 = [ob2.matrix_world * Vector(b) for b in ob2.bound_box]

diffs = [v2 - v1 for  v1, v2 in zip(bbox1, bbox2)]
return all(d.length < TOL for d in diffs)
#return sum(diffs, Vector()).length < TOL

obs = {}
keys = []
for ob in context.selected_objects:
ob.select = False
if ob.type != 'MESH':
continue
# make a key from faces, edges, verts
mesh = ob.data
key = "%d_%d_%d" % (len(mesh.polygons), len(mesh.edges), len(mesh.vertices))
obs[ob.name] = key
keys.append(key)

possible_dupes = set([x for x in keys if keys.count(x) > 1])
print("-" * 40)
while possible_dupes:
p = possible_dupes.pop()
dupes = sorted(name for name, value in obs.items() if value == p)
while dupes:
original = dupes.pop(0)
original_ob = scene.objects.get(original)

for dupe in dupes:

dupe_ob = scene.objects.get(dupe)
if dupe_ob.select:
continue

if test(original_ob, dupe_ob):
dupe_ob.select = True
scene.objects.active = dupe_ob
print("possible dupe: ", dupe, " of original: ", original)


Result on your file. Dupe objects moved to layer 3 on left. Reduced file size from 91 to 47 meg on removal of dupes.

Updated for version 2.8

Some minor changes for the new API, notably ob.select_set() and ob.select_get() for setting and getting selection, and @' for matrix / vector multiplication

import bpy
from mathutils import Vector
context = bpy.context

scene = context.scene
view_layer = context.view_layer
TOL = 1.0e-3 # reduced tolerance.

# routine to text matches on bound box.
def test(ob1, ob2):
# test if ob1 and ob2 which have same face/edge/vert count are same
bbox1 = [ob1.matrix_world @ Vector(b) for b in ob1.bound_box]
bbox2 = [ob2.matrix_world @ Vector(b) for b in ob2.bound_box]

diffs = [v1 - v2 for  v1, v2 in zip(bbox1, bbox2)]
return all(d.length < TOL for d in diffs)
#return sum(diffs, Vector()).length < TOL

obs = {}
keys = []
for ob in context.selected_objects:
ob.select_set(False)
if ob.type != 'MESH':
continue
# make a key from faces, edges, verts
mesh = ob.data
key = "%d_%d_%d" % (len(mesh.polygons), len(mesh.edges), len(mesh.vertices))
obs[ob.name] = key
keys.append(key)

possible_dupes = set([x for x in keys if keys.count(x) > 1])
print("-" * 50)
while possible_dupes:
p = possible_dupes.pop()
dupes = sorted(name for name, value in obs.items() if value == p)
while dupes:
original_ob = scene.objects.get(dupes.pop(0))
for dupe in dupes:

dupe_ob = scene.objects.get(dupe)
if dupe_ob.select_get():
continue

if test(original_ob, dupe_ob):
dupe_ob.select_set(True)
view_layer.objects.active = dupe_ob
print("possible dupe: ", dupe, " of original: ", original_ob.name)
`
• Thanks for the reply and the script. I have paste the script and run some double it remove and some it remove original also the result is in the above in the question section. – atek Aug 8 '17 at 10:23
• more than 300Mb – atek Aug 8 '17 at 11:11
• new update script still i think not working. It is selected but confuse which to delete. If i delete the left then the door panel is not selected in the other side. pasteall.org/pic/index.php?id=117849 – atek Aug 8 '17 at 13:17
• i have attach the file have u done experiment on it – atek Aug 8 '17 at 15:26
• Thanks for your beautiful script. When your script it help me to finish my model above is my final render. – atek Aug 9 '17 at 18:08