6
$\begingroup$

I have a script which adds a material to an object. The script is using bpy.ops.object.material_slot_add(). However, this only works when the script is used from the text editor. It has polling/context errors when used differently.

What Blender 2.75a API commands provide the low level equivalent to bpy.ops.object.material_slot_add()?

$\endgroup$
3
  • $\begingroup$ I use this operator often from the 3D view and console. It is not limited to the text editor. It also works in object mode, edit mode, sculpt mode, weight paint, texture paint... Where are you running the script from? You might have a panel in some specific screen that might be out of context, but you can probably override this context and run the operator anyway (blender.stackexchange.com/search?q=context+override) $\endgroup$
    – TLousky
    Oct 12, 2015 at 13:21
  • $\begingroup$ The command will be used in a function which will be passed to the render handler: bpy.app.handlers.render_pre.append() . Because of challenges in getting the override set up properly and a desire to make create scripts which operate independent of the context, I'm trying to convert all bpy.ops to low level equivalents. $\endgroup$
    – Ed Tate
    Oct 12, 2015 at 13:26
  • $\begingroup$ I don't think you have another way to add a material slot via python. I think I tried finding one before. Maybe some other person here knows something I don't. Anyway, try the solution in the answer below. Small trivial thing, but sometimes those are the hardest to debug. $\endgroup$
    – TLousky
    Oct 12, 2015 at 13:28

2 Answers 2

6
$\begingroup$

Example code

Adds two material slots, m1 (if there is already an active material slot it will replace it with m1) and m2

import bpy

mat1 = bpy.data.materials.new("m1")
mat2 = bpy.data.materials.new("m2")

ob = bpy.context.object

ob.active_material = mat1
ob.data.materials.append(mat2)

An empty slot can be added with

ob.data.materials.append(None)

Hence can add either data or object materials this way by setting the slot link.

import bpy

materials = (
    (bpy.data.materials.new("RED"), 'DATA'),
    (bpy.data.materials.new("BLUE"), 'OBJECT'),
    )

ob = bpy.context.object
me = ob.data

for m, link in materials:

    # add a material adds a slot
    print(m.name)
    me.materials.append(None)

    slot = ob.material_slots[-1]
    slot.link = link
    slot.material = m

Thankyou to @Lambdadelta for pointing out

enter image description here Note if "Link Materials to" set to "Object" instead of default "Object Data" in the blender preferences, then ob.data.materials.append(None) adds a slot to all linked objects, whereas bpy.ops.object.material_slot_add() adds only to the active object

$\endgroup$
2
  • 1
    $\begingroup$ Note if "Link Materials to" set to "Object" instead of default "Object Data" in the blender preferences, then ob.data.materials.append(None) adds a slot to all linked objects, whereas bpy.ops.object.material_slot_add() adds only to the active object $\endgroup$ Mar 28, 2020 at 4:36
  • $\begingroup$ @Lambdadelta cheers Added as edit.. Tricky to get around as materials.clear() as doesmaterials.pop(index=index) $\endgroup$
    – batFINGER
    Mar 28, 2020 at 12:08
0
$\begingroup$

The only case I can think of where this operator will not work is that the object you want to add a material slot to is not selected and active. Make sure of both in your script before calling the operator:

myObj.select = True
bpy.context.scene.objects.active = myObj
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .