Utility_Apps/Blender/addons/Select Contiguous Material/__init__.py

91 lines
2.6 KiB
Python

bl_info = {
"name": "Select Contiguous Material",
"author": "ChatGPT + Ryan Schultz",
"version": (1, 1, 0),
"blender": (3, 0, 0),
"location": "Edit Mode > Face Select",
"description": "Select connected face regions sharing the same material as any selected face",
"category": "Mesh",
}
import bpy
import bmesh
class MESH_OT_select_contiguous_material(bpy.types.Operator):
"""Expand selection to all connected faces that share the same material as the selected faces"""
bl_idname = "mesh.select_contiguous_material"
bl_label = "Select Contiguous Material (Multi)"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
obj = context.edit_object
return obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH'
def execute(self, context):
obj = context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)
bm.faces.ensure_lookup_table()
# collect all initially selected faces (seeds)
seed_faces = [f for f in bm.faces if f.select]
if not seed_faces:
self.report({'WARNING'}, "Select at least one face")
return {'CANCELLED'}
# remember material per seed
seed_materials = {f: f.material_index for f in seed_faces}
# clear selection (we will rebuild it)
for f in bm.faces:
f.select = False
visited = set()
stack = list(seed_faces)
while stack:
face = stack.pop()
if face in visited:
continue
visited.add(face)
# determine which material this flood belongs to
# (it inherits the material of the original seed that reached it)
for seed, mat in seed_materials.items():
if face.material_index == mat:
face.select = True
for edge in face.edges:
for linked_face in edge.link_faces:
if linked_face not in visited:
stack.append(linked_face)
break
bmesh.update_edit_mesh(me)
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(
MESH_OT_select_contiguous_material.bl_idname,
text="Contiguous Material (Multi)"
)
def register():
bpy.utils.register_class(MESH_OT_select_contiguous_material)
bpy.types.VIEW3D_MT_select_edit_mesh.append(menu_func)
def unregister():
bpy.types.VIEW3D_MT_select_edit_mesh.remove(menu_func)
bpy.utils.unregister_class(MESH_OT_select_contiguous_material)
if __name__ == "__main__":
register()