Thanks for reading. I often import huge mechanical assemblies into blender. The assemblies contain hundreds of fasteners/screws/washers and I would like to instance these - to save memory. The first problem is that blender does not know that these objects are the same. Is there a short python script to choose parts in the scene that have the same volume or even verts or faces? How would I use the script? TIA
1 Answers
Select the object(s) you want to find similar ones for and run this script:
import bpy
import math
import bmesh
gets number of vertices and faces, surface area and volume
def get_extent_data(obj):
# bmesh stuff needed for surface area and volume
mesh = obj.to_mesh()
mesh.transform(obj.matrix_world) # could have for example unapplied scaling
bm = bmesh.new()
bm.from_mesh(mesh)
return (
len(obj.data.vertices), # num vertices
len(obj.data.polygons), # num faces
sum(face.calc_area() for face in bm.faces), # surface area
bm.calc_volume(signed=True) # volume
)
helper function to find an extent data key
def find_extent_key(extent_data, table):
# we need to be careful when comparing surface area and volume
def compare_extent_data(a, b):
# make rel_tol greater if you experience that
# objects don't get selected if you think they should
return (a[0] == b[0] and a[1] == b[1] and # compare vertices and faces
math.isclose(a[2], b[2], rel_tol=1e-5) and # compare surface area
math.isclose(a[3], b[3], rel_tol=1e-5)) # compare volume
for key in table.keys():
if compare_extent_data(key, extent_data):
return key
parses the scene and groups objects with same extent
def create_equal_extent_objects_table():
table = {}
for obj in bpy.data.objects:
if obj.type != "MESH":
continue
extent_data = get_extent_data(obj)
key = find_extent_key(extent_data, table)
if key:
table[key].append(obj)
else:
table[extent_data] = [obj]
return table
create our table which contains groups of objects seen as equal
table = create_equal_extent_objects_table()
find all objects which have same extent data as the selected ones respectively
for selected in bpy.context.selected_objects:
if selected.type != "MESH":
continue
extent_data = get_extent_data(selected)
key = find_extent_key(extent_data, table)
if key:
for obj in table[key]:
obj.select_set(True)
The script is not much optimized (detecting linked duplicates or stuff like this), so it could be slow for big scenes. The key function is get_extent_data which returns the number of vertices, number of faces, surface area and volume of a mesh. With these four data points you should get pretty good hits. Only using the number of vertices for example as comparison data will, in the general case, return a lot of false positives. If you know your scene better and that's applicable, just rewrite get_extent_data to return less data and adjust compare_extent_data accordingly.
- 3,384
- 1
- 3
- 18