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?
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.
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
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âŚ
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âŚ
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 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.
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?