1

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

JB Riley
  • 791
  • 3
  • 9

1 Answers1

2

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.

taiyo
  • 3,384
  • 1
  • 3
  • 18