0

I have 200 material slots. I know how to iterate through them, but I cannot make them active.

for o in bpy.data.objects:
    for m in o.material_slots:
        if "screen" in m.name:
            bpy.ops.mesh.select_similar(type='MATERIAL', threshold=0.01)

But I cannot execute the last operator, as I cannot make them active material.

I have to just select similar materials by name and separate them as a new objects. Unfortunately, I cannot way of selecting textures by name, so I cannot execute select_similar and separate operators.

To be more precise, I have a .obj file. It contains 200 materials. I should separate it into 2 groups, group 1 is wall, and group 2 is furniture. I am able to iterate through material_slots and find certain materials which I need. But I cannot select them in edit mode. I have every material's name, I should select 20 or 30 of them and separate them into new objects.

Blunder
  • 13,925
  • 4
  • 13
  • 36
  • 1
    Hello and welcome. your operator will throw an exception because you did not specify the context https://blender.stackexchange.com/questions/6101/poll-failed-context-incorrect-example-bpy-ops-view3d-background-image-add – Harry McKenzie Dec 29 '22 at 12:15
  • I have to just select similar materials by name and seperate them as a new object. Unfortunetly I cannot way of selecting textures by name, so I cannot execute select_similar and seperate operators. I have been stucked for a week. – Sarvar Shodiyev Dec 29 '22 at 12:29
  • Do you need the operator or is a bpy.context.object.active_material_index = idx good enough to make the material active? It's not really clear what you are trying to achieve. Select Similar > Material has no threshold, and it looks like it only works in Edit mode. A bit more context on what your goal is would help. – Blunder Dec 29 '22 at 16:18
  • Ok, the threshold is shown in the Python console. But bpy.ops.mesh.select_similar(type='MATERIAL', threshold=0.01) selects all faces with the material that the active face in Edit mode has. So why do you need to loop through all material slots and look for a material with "screen" in the name? – Blunder Dec 29 '22 at 16:33
  • sorry, it is my very first post in forums. To be more precise, I have a .obj file. It contains 200 hundred materials. I should seperate it 2 groups, group1 is wall, group2 is furnitures. I am able to iterate through material_slots and find certain materials which I need. BUT i cannot select them in edit mode. I have every materials name, I should select 20 or 30 of them and seperate into new group. – Sarvar Shodiyev Dec 30 '22 at 06:46
  • Don't worry. Welcome :) I think (and hope) what you're looking for is bpy.ops.object.material_slot_select() in addition to the ...active_material_index = idx from the comment above. I'll post a complete script below. – Blunder Dec 31 '22 at 03:07

1 Answers1

1

Here is a script that checks the material slots of all mesh objects. If there is the word screen in the material's name then it selects the vertices of this material and checks the next material. After the check, the selection is separated into a new object if there were matches.

I think what you were actually looking for are lines 31 and 32:

31:         bpy.context.object.active_material_index = idx
32:         bpy.ops.object.material_slot_select()

but you also need to select the object to have the correct context (line 21) and do a few other safety checks.

The complete script looks like this:

import bpy

save objects because the operation 'Separate Selection' creates new objects

objects = set(obj for obj in bpy.data.objects)

ensure we are in object mode

if bpy.context.active_object.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

clear object selection so the context is correct

bpy.ops.object.select_all(action='DESELECT')

for obj in objects:
if obj.type != 'MESH': print(f"Skipping {obj.name} of type {obj.type}") continue

print(f"Checking materials of {obj.name} ")

# select object, switch to edit mode & clear vertex selection
bpy.context.view_layer.objects.active = obj
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='DESELECT')

# check material slots
found = 0
for idx, slot in enumerate(obj.material_slots):
    if "screen" in slot.material.name:              #  <-- materials to look for
        print(f"Found material slot #{idx}: {slot.name}")
        # select the material slot, then select all vertices with this material
        bpy.context.object.active_material_index = idx
        bpy.ops.object.material_slot_select()
        found += 1

# do 'Separate Selection' if we have a selection from at least one match
if found > 0:
    bpy.ops.mesh.separate(type='SELECTED')

# switch back to object mode 
bpy.ops.object.editmode_toggle()

Example output for materials with "Blue" in their name:

Checking materials of Cube
Found material slot #1: Ocean Blue
Found material slot #2: Deep Blue
Found material slot #3: Blue Sky
Checking materials of Cylinder
Skipping Camera of type CAMERA
Skipping Light of type LIGHT
Checking materials of Cube default
Checking materials of Sphere
Found material slot #1: Night Blue Sphere
Blunder
  • 13,925
  • 4
  • 13
  • 36
  • thank you a lot bro, that is exactly what I was searching but couldn`t find in forums and Blender API documentations. Thank you – Sarvar Shodiyev Dec 31 '22 at 17:46
  • Hello everybody! May I ask you about the script from Blunder? I've tried this script in Blender 3.6 but it leaves me with this error:

    File "C:\Program Files\Blender Foundation\Blender 3.6\3.6\scripts\modules\bpy\ops.py", line 113, in call ret = _op_call(self.idname_py(), None, kw) RuntimeError: Error: Nothing selected

    Allthough with print statement I verified in the console, that the correct slot was found: Checking materials of Plane Found material slot #1: metal_ornaments_29_55

    Mark as Asset

    I am trying to to mark the active material slot as an asset! Thx! :-)

    – Taffi Sep 14 '23 at 19:32
  • Hi there. The "ops.py" is a Blender internal script. I guess the error is more likely in your script ;-) It looks like there is something not selected as expected. It's hard to tell what's wrong without seeing your script. Feel free to post a new question, show your script - or even better an example that causes the error, the full error message including the calls and line numbers, and link this question here so we know what you have done. – Blunder Sep 16 '23 at 13:46