To sort the list of materials in the object’s material slots in Blender in the desired way, for example, alphabetically, we can use the function we created earlier to switch materials in material slots.
First, let’s create a list of names of all materials of the current active object.
1 2 3 |
mat_names = [_mat.name for _mat in bpy.context.active_object.data.materials] # ['red', 'green', 'blue', 'cyan'] |
As we can see, the order of the material names corresponds to the order of the materials in material slots.
Let’s sort it alphabetically to get the list in the order we need.
1 2 3 |
mat_names.sort() # ['blue', 'cyan', 'green', 'red'] |
The index of the material name in the sorted list corresponds to the required ordinal number – it should be located in this place in the object’s material slots.
Therefore, we can get the required index for each material, where to put it, simply by walking through the list using the enumerate() function.
1 |
for _slot_to_idx, mat_name in enumerate(mat_names): |
For each material, we need to determine the index where it is currently located in the list of material slots. After that, we can call our function, specifying both indexes, to switch materials in the slots. Thus, the material gets to “the right” place.
Let’s find the current index of the material by its name:
1 2 3 |
slot_from_idx = next((_idx + _slot_to_idx for _idx, _material in enumerate(bpy.context.object.data.materials[_slot_to_idx:]) if _material.name == mat_name), None) |
On each loop pass, one material, starting from the beginning of the list (from the top of slots list) is put to the right place. Therefore, to search for a material, we use a slice, starting from the current iteration of the loop, so as not to check materials that are already placed correctly in their slots.
1 |
bpy.context.object.data.materials[_slot_to_idx:] |
By selecting a material with the current name from this slice, we get its index, additionally adding the number of the loop iteration to the index to take the slice into account.
Having received three input parameters for our function:
- object – bpy.context.object
- index from where to move the material – slot_from_idx
- and index to move it – slot_to_idx
we can call the function to switch the materials.
1 2 |
if slot_from_idx: switch_materials(bpy.context.object, slot_from_idx, _slot_to_idx) |
After we walk through the entire cycle of materials, all materials in the slots will be arranged alphabetically.
All code:
1 2 3 4 5 6 7 8 9 |
mat_names = [_mat.name for _mat in bpy.context.active_object.data.materials] mat_names.sort() for _slot_to_idx, mat_name in enumerate(mat_names): slot_from_idx = next((_idx + _slot_to_idx for _idx, _material in enumerate(bpy.context.object.data.materials[_slot_to_idx:]) if _material.name == mat_name), None) if slot_from_idx: switch_materials(bpy.context.object, slot_from_idx, _slot_to_idx) |