I was wondering if there is a way (or python script) to convert multiple identical meshes into instances? - where all other identical meshes are referring (instanced) to the first identical mesh e.g., BALUSTER.001.
As long as the origins of the various objects are in correct relation to each object, there is a simple way to do this. Select all objects that are supposed to share the same mesh data, then - in the 3D View - hit Ctrl + L to open the link menu. From there, choose
This will re-use the mesh data from the last selected object on all other instances. You can tell that they are instances in the mesh data tab of the outliner. The user count (number next to the data name) should have appeared and increased to reflect the number of meshes that re-use the data:
An alternative answer to the same question using Python works as follows: I assume that the objects coming in are consistently named, and the restrictions of origin placement are the same as with the other answer I gave. With consistent naming I mean this:
my_obj_01 is supposed to share the data with my_obj_01.001, ..., my_obj_01.015, ... my_obj_01 is NOT supposed to share the data with my_obj_02
If this is the case, then the following script will do what you request in one shot for the whole selection. So make sure to select the items you want to operate on first. If that's the whole scene, then so be it:
import bpy import os # purpose of this script is to link object data of objects by name # the pattern used is that if an object name has duplicates following # Blender's .001, .002, .003 syntax, the mesh data will be linked # between them # consider only mesh objects objs = sorted([x for x in bpy.context.selected_editable_objects if x.type == 'MESH'], key = lambda x: x.name) # get a list of the names of the objects above, stripped from any .001, .002 etc # this will create duplicate name entries enabling us to find the elements we want to link obj_names_stripped = [os.path.splitext(x.name) for x in objs] # now iterate over the name list. # Getting an enumerator here too to be able to index the object later on for i, obj_name in enumerate(obj_names_stripped): # check for i=0 to skip the very first item if i != 0: # check if the current item has the same name when stripped # than the previous item if obj_name == obj_names_stripped[i-1]: # link the object datas of obj[i-1] and obj[i] objs[i].data = objs[i-1].data
A few notes
- I am abusing the os module here to strip the .001, .002 etc that Blender adds when importing. However, be warned: I currently do NOT check if you have an object called
my_obj.test. My script then would force such an object to share its mesh data with
my_obj.other_test, as all I do is strip anything behind a dot.
- I am using the trick to sort the list of objects you have selected using the
sorted(list, key=function)method that Python provides. By doing so I only need to sequentially iterate over the whole object list once, and compare an item with the one before it. If their names are identical, I link the latter item to the one before, effectively daisy-chaining the mesh data of the first object found through to all copies
- I use Pythons
enumeratefunction to provide me a tuple of index and object from the name list, so I can access the mesh object from another list that has the same sorting as the name list