Find duplicate objects or vertices without removing them

I have several objects in my scene, and I want to see if any are the same.
For example: I have a town, and the town has several trees, which look very similar but have very different names. I want to see if all the trees are the same, without removing them. I just want to see if there are any duplicates.

This might have already been done, however I was unable to find information on it. If this has not been already done, what would be the best place to look so that I can try to write something?

Select one of those objects and press shift-L then choose object data. This selects all objects sharing the same mesh datablock

I tried it, however the only selected object was the original one. The objects are not linked or derived from one another, instead they just have very similar points but in different coordinates.

Ok, I am not shure what you meant with duplicates and what do you want to achieve.

Maybe use L in editmode to select connected meshes.


Sorry, I wanted to see if two objects are the same based on the distance between each point of the object.
For example, these two fences look the same to me, but I want to find out if they really are the same. They aren’t derived from each other, so they have no connection except that maybe the distance between each point is the same.
I wasn’t able to access the Shift+L menu while in Edit Mode.

So the assumption is that there’s a a lot of unnecessary copies of the same mesh when they could be instances? Ie. creation with shift+d instead of alt +d

Assuming the objects have been transformed in object mode, and their origins haven’t been disturbed, you can just compare the points of each object based on proximity. KDTrees should be the best way to do that. Find the nearest points of each mesh and calculate the mean of the distances.

If the objects have had their origins modified, you’ll first need to try finding matches by bounding box similarity. Then transform the objects so their bounding boxes match and test each orientation where that’s possible and then do the point location comparison.

I don’t know your experience with Python and bpy so sorry if that’s all a bit much :slight_smile:
The first part should be pretty easy to implement. The second, specifically finding matching bounding boxes, is a little more math intensive.

I am not sure what an instance is. My idea was to have a collection of models in a scene that I am importing from one larger file, and export all “unique” objects. (By that I mean to export every object besides duplicates of the same object. So in my example I would only export one fence object, and leave the rest)
But to do that I need to first find if any objects are duplicated, and while not necessary for exporting, I need all the duplicates for something else.

I am not sure if their origin has been modified, they are loaded in from a file which just states groups of vertices, and when I try to move them, their location that they are in when I import the file is 0,0. They also have not been transformed, they are imported already in place. I can share original file if needed.

The problem is that it’s not easy to say if a mesh is identical to another mesh without doing some comparisons between their data.

In Blender there are two ‘layers’ to an object, there is the upper ‘object’ level which has information about the location, rotation, etc. Under that is a ‘data’ layer which in this case is probably a ‘mesh’. You can have multiple top layer objects that reference the same data layer, which is then called an ‘instance’. In that case it’s very easy to tell what objects are the same, because they are ‘instances’ of the same underlying data.

But when you create copies of an object (vs creating an instance of it), you end up with copies of the data which may or may not be different from the original. But there isn’t a quick way of determining if the copied data is the same.

If all the trees are located at 0,0,0, but appear in different locations, then the position of each vertex is going to be different for each tree, even if they are identical. So thing’s get more tricky… If they are also rotated and/or scaled inside the mesh data (as opposed to the object data), then they really are no longer identical models…

If they aren’t scaled, then comparing the distance between verts might give you decent results? Like if the mesh is technically the same, the distance between verts shouldn’t change even if the overall locations are totally different…

They don’t seem to be scaled, only different coordinates and rotation.
Is there any other way to see if the mesh is the same besides Shift+L?

I’m not aware of anything that will really do what you want… It does seem like something someone may have already made a python script to do…

But unless you can find something or someone knows of one, you’re probably going to need to write a script to do what you want here. Like I said I would probably start with something that compares the distances between verts between meshes, as those should remain unchanged if the base mesh has only been translated/rotated…

Is there a way to get the mesh of an object from its name instead of having to select the object?

All the meshes exist independently of objects in bpy.data.meshes. There is not necessarily any relation between object names and mesh names. Also any mesh type objects mesh can be accessed via object.data.

But if you want to select the duplicates in your scene or whatever, you need to interact with the objects and set their selection state. Also note that if two objects have a data with the same name, then it’s the same data (but I don’t think you will find that to be the case in the file you’re working with).

You should put the file somewhere so we can look at it?

I put the file on my Google Drive
https://drive.google.com/drive/folders/1yTACm6y07HotPm6w9acUePLr60RNnaC0?usp=sharing

I can provide information on the file format, and you also need XNALara Mesh plugin for Blender to load it. Might take a couple minutes to loud.
The objects are also not centered at the origin, you need to change view distance to large number and then zoom out


If you did it intentionally from the beginning you’d have a number showing you how many objects were using the exact same one piece of mesh data.

My advice is to pick a tree, give its mesh data a name, then go to all the other trees and set them to use the same mesh data. If the scene still looks good then job’s done.




Take 2 trees, put them in exactly the same location/rotation scale. If they look identical, they probably are. Join them into a single object. Let’s say both trees each have 1000 verts. After joining them the vert count would be 2000. Do a merge by distance. If the vert count goes down to exactly 1000 then they were probably identical trees.

I didn’t create the file, and I would take your advice and do what you said, but I have several trees in each file, and a lot of files. I am not trying to render the scene, I need to get a list of all object names that are duplicates so that I can only export non-duplicates.

Okay I had a look over the file and unfortunately those trees have slightly different scaling applied to them. So while they look practically identical, the size of the faces and the length of the edges are just a little bit different between them…

That makes it impossible to find exact matches between meshes, because they don’t exist. You would have to use some sort of fuzzy matching where some range of values were acceptable…

Anyway here is the comparison code I would use:

import bmesh
test = bmesh.new()
test.from_mesh(some_mesh)
comp = bemsh.new()
comp.from_mesh(some_other_mesh)
delta = 0.005 # set margin of error allowed

if len(test.edges) == len(comp.edges):
    test.edges.ensure_lookup_table()
    comp.edges.ensure_lookup_table()
    for idx in range(len(test.edges)):
        len1 = test.edges[idx].calc_length()
        len2 = comp.edges[idx].calc_length()
        if abs(len1 - len2) > delta:
            print("No match")
            break

If this produces no output, then all the edges were within the margin for error of each other and thus the objects are most likely the same mesh. You should be able to take it from here to do what you need to do?

Thank you for the comparison code.
Is there any way to find or select a mesh based on the name of the object? Like a select object command that is based off of the object name? (I guess like select_object.objectname)
Again, thank you very much

The objects are all stored under their names. You can just reference them from bpy.data.objects[‘object_name’], no need to use any commands. If you want to set a object as being selected, just change the selected state in its properties.

Have you tried select pattern?

image

Assuming you duplicated objects without renaming them they all should follow name.XXX pattern:

After that you can relink all object copies so they share same mesh data (geometry, materials, uvs, etc) with Ctrl+L → Link Object Data

image

image

import bpy
import bmesh

count = 0
count2 = 0
count3 = 0
LIST = []

for collection in bpy.data.collections:
    #print(collection.name)
    for obj in collection.all_objects:
        LIST.append(obj.name)
    
for i in LIST:
    me = bpy.data.objects[i]
    for j in LIST:
        #me = bpy.data.objects[i]
        me2 = bpy.data.objects[j]
        
        #print(i)
        bm = me.data
        bm2 = me2.data
           
        test = bmesh.new()
        test.from_mesh(bm)
        comp = bmesh.new()
        comp.from_mesh(bm2)
        delta = 0.005 # set margin of error allowed

        if i != j:
            if len(test.edges) == len(comp.edges):
                test.edges.ensure_lookup_table()
                comp.edges.ensure_lookup_table()
                for idx in range(len(test.edges)):
                    len1 = test.edges[idx].calc_length()
                    len2 = comp.edges[idx].calc_length()
                    if abs(len1 - len2) > delta:
                        print("No match", i,"!=",j)
                        count2 += 1
                        break
                    elif abs(len1 - len2) <= delta:
                        print("Match", i,"=",j)
                        count += 1
                        break
        elif i == j:
            count3 += 1


print('Total Equal Comparisons:', count)
print('Total Same Objects', count3)

print('Total Not Equal Comparisons:', count2)

I use this code to compare the objects. However, it is returning an incorrect number of objects.
The file I imported into Blender has ~1000 objects, meaning I would have about 1,000,000 comparisons. I only have ~230,000 comparisons. Is it possible that the script is missing objects, or just not counting them? I used the same file that I put on my Google Drive.

Also, to increase margin of error, would I increase the delta variable, or decrease it?