Codixie

Сортирует материалы на меше

Сортирует материалы на меше

1import bpy
2import re
3from collections import defaultdict
4
5def extract_id(material_name):
6    """Извлекает числовой ID из имени материала"""
7    match = re.match(r'id(\d{1,3})_', material_name)
8    return int(match.group(1)) if match else None
9
10def process_mesh(obj):
11    """Основная функция обработки меша"""
12    print(f"\nОбработка объекта: {obj.name}")
13    
14    # 1. Сохраняем полную карту назначений материалов
15    material_assignments = {
16        'polygons': defaultdict(list),
17        'edges': defaultdict(list),
18        'vertices': defaultdict(list)
19    }
20    
21    # Сохраняем назначения для полигонов
22    for poly in obj.data.polygons:
23        if poly.material_index < len(obj.material_slots):
24            mat_name = obj.material_slots[poly.material_index].material.name
25            material_assignments['polygons'][mat_name].append(poly.index)
26    
27    # Сохраняем назначения для рёбер (если есть)
28    if hasattr(obj.data, 'edges'):
29        for edge in obj.data.edges:
30            if hasattr(edge, 'material_index'):
31                if edge.material_index < len(obj.material_slots):
32                    mat_name = obj.material_slots[edge.material_index].material.name
33                    material_assignments['edges'][mat_name].append(edge.index)
34    
35    # Сохраняем назначения для вершин (если есть)
36    if hasattr(obj.data, 'vertices'):
37        for vert in obj.data.vertices:
38            if hasattr(vert, 'material_index'):
39                if vert.material_index < len(obj.material_slots):
40                    mat_name = obj.material_slots[vert.material_index].material.name
41                    material_assignments['vertices'][mat_name].append(vert.index)
42    
43    # 2. Собираем уникальные материалы и их оригинальные индексы
44    materials = {}
45    for i, slot in enumerate(obj.material_slots):
46        if slot.material:
47            materials[slot.material.name] = {
48                'material': slot.material,
49                'original_index': i
50            }
51    
52    # 3. Разделяем материалы на две группы
53    materials_with_id = []
54    materials_without_id = []
55    
56    for mat_data in materials.values():
57        mat = mat_data['material']
58        if extract_id(mat.name) is not None:
59            materials_with_id.append(mat)
60        else:
61            materials_without_id.append(mat)
62    
63    # 4. Сортируем материалы
64    materials_with_id_sorted = sorted(materials_with_id, key=lambda x: extract_id(x.name))
65    materials_without_id_sorted = sorted(materials_without_id, key=lambda x: x.name.lower())
66    final_materials = materials_with_id_sorted + materials_without_id_sorted
67    
68    # 5. Создаем mapping имени материала на новый индекс
69    name_to_new_index = {mat.name: i for i, mat in enumerate(final_materials)}
70    
71    # 6. Очищаем и пересоздаем material slots
72    obj.data.materials.clear()
73    for mat in final_materials:
74        obj.data.materials.append(mat)
75    
76    # 7. Восстанавливаем назначения
77    # Для полигонов
78    for mat_name, poly_indices in material_assignments['polygons'].items():
79        if mat_name in name_to_new_index:
80            new_index = name_to_new_index[mat_name]
81            for poly_idx in poly_indices:
82                obj.data.polygons[poly_idx].material_index = new_index
83    
84    # Для рёбер
85    if hasattr(obj.data, 'edges'):
86        for mat_name, edge_indices in material_assignments['edges'].items():
87            if mat_name in name_to_new_index:
88                new_index = name_to_new_index[mat_name]
89                for edge_idx in edge_indices:
90                    obj.data.edges[edge_idx].material_index = new_index
91    
92    # Для вершин
93    if hasattr(obj.data, 'vertices'):
94        for mat_name, vert_indices in material_assignments['vertices'].items():
95            if mat_name in name_to_new_index:
96                new_index = name_to_new_index[mat_name]
97                for vert_idx in vert_indices:
98                    obj.data.vertices[vert_idx].material_index = new_index
99    
100    print(f"Уникальных материалов: {len(final_materials)}")
101    return len(final_materials)
102
103# Основное выполнение
104if __name__ == "__main__":
105    selected_objects = [obj for obj in bpy.context.selected_objects if obj.type == 'MESH']
106    if not selected_objects:
107        print("Ошибка: Не выбрано ни одного меша!")
108    else:
109        # Сохраняем текущий режим
110        prev_mode = bpy.context.object.mode if bpy.context.object else 'OBJECT'
111        if prev_mode != 'OBJECT':
112            bpy.ops.object.mode_set(mode='OBJECT')
113        
114        total_processed = 0
115        for obj in selected_objects:
116            total_processed += process_mesh(obj)
117        
118        # Восстанавливаем режим
119        if prev_mode != 'OBJECT':
120            bpy.ops.object.mode_set(mode=prev_mode)
121        
122        print(f"\nОбработка завершена! Обработано объектов: {len(selected_objects)}, материалов: {total_processed}")