# Python - Set material to material slot

I am using the Blender Internal render engine. I have an material slot with no material assigned to it. How can I assign a material to a slot using python? This should work in edit mode as well. Basically I would like to assign materials to specific faces.

This code creates 10 materials and appends it to the active object (should be a mesh). The diffuse color of every material is random. The .material_index poperty is set to the new materials by index (even if the object has materials assigned before the operation).

import bpy
from random import random

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

mat_offset = len(me.materials)
mat_count = 10

mats = []
for i in range(mat_count):
mat = bpy.data.materials.new("Mat_%i" % i)
mat.diffuse_color = random(), random(), random()
me.materials.append(mat)

# Can't assign materials in editmode
bpy.ops.object.mode_set(mode='OBJECT')

i = 0
for poly in me.polygons:
if poly.select:
poly.material_index = i % mat_count + mat_offset
i += 1


If you want to use UV mapped textures, you'll also have to deal with me.uv_layersand me.uv_textures. It's not enough to assign materials to faces, you also need to set the texture image for every face.

• What if I want to use the face selection from the select random tool? – Vader Apr 13 '14 at 14:03
• Updated my example to only assign new materials to selected polygons. Note that if there's no material before the operation, unselected polygons will use the first material (.material_index has a default of 0, which is automatically the first material). – CodeManX Apr 13 '14 at 21:27
• @CoDEmanX I want to go over all of my materials and select (or get indices of) faces to which that specific material has been applied to. I haven't been able to find a good solution for doing that as of now. I would appreciate if you can take a look at my question here and see if you can offer a solution? – Amir Mar 17 '18 at 4:59

That would be -

import bpy

D = bpy.data

if len(D.objects['Cube'].material_slots) < 1:
# if there is no slot then we append to create the slot and assign
D.objects['Cube'].data.materials.append(D.materials['Material'])
else:
# we always want the material in slot[0]
D.objects['Cube'].material_slots[0].material = D.materials['Material']

• This doesn't work when I want to assign random faces a material in edit mode. – Vader Apr 11 '14 at 13:02
• @Vader Perhaps the source of this addon has some clues. – gandalf3 Apr 12 '14 at 21:19
• @gandalf3 I already know how to do this on object level. I need to do it in edit mode though. This tut only does objects. – Vader Apr 12 '14 at 21:26
• @Vader Your question is assigning a material to a slot not assigning a material to faces. – sambler Apr 13 '14 at 8:39
• @sambler updated question. – Vader Apr 13 '14 at 11:20

This sequence would assign the currently selected material to the first slot:

bpy.context.object.active_material_index = 0
bpy.ops.object.material_slot_assign()


The material-utils addon makes heavy use of the API methods for materials, there you should find further details. SVN space_view3d_materials_utils.py

• I need to specify the material that is assigned though – Vader Apr 10 '14 at 21:29

Abandon the approach of edit mode/non-edit mode and just focus on the datablock. Materials for faces are specified via material_index inside the datablock of a mesh type object.

Add a Suzanne mesh to the scene and try this code:

import bpy, random

ob = bpy.data.objects.get("Suzanne")
if ob != None:
# Create a materials.
mat_one = bpy.data.materials.get("mat_one")
if mat_one == None:
mat_one = bpy.data.materials.new("mat_one")
mat_one.diffuse_color = (random.random(),random.random(),random.random())

mat_two = bpy.data.materials.get("mat_two")
if mat_two == None:
mat_two = bpy.data.materials.new("mat_two")
mat_two.diffuse_color = (random.random(),random.random(),random.random())

ob.data.materials.append(mat_one)
ob.data.materials.append(mat_two)

# Determine random count and poly count.
rnd_face_count = 12
l = len(ob.data.polygons)

# Note: By default all faces have a material index of 0.
for i in range(rnd_face_count):
# Generate a random face index.
rnd_face_index = random.randint(0,(l-1))
ob.data.polygons[rnd_face_index].material_index = 1


This is not the cleanest code but it shows one way to accomplish the task mentioned. If you run this code twice, however, you will discover that you are building up a list of new materials on the Suzanne object.

I used sambler's answer for the .append() idea,
but I referenced context, instead of name:
(R, G, B are standard 0-255 values)

obj = bpy.context.object
colorstring  = 'r' + str(R) + ' g' + str(G) + ' b' + str(B)

if colorstring in bpy.data.materials.keys():
obj.data.materials.append(bpy.data.materials[colorstring])

else:
material  = bpy.data.materials.new(colorstring)
obj.data.materials.append(material)
material.diffuse_color  = (R / 255, G / 255, B / 255)
bpy.ops.object.material_slot_assign()


Just to put in my two cents:

I have created my object, and I have a list that contains the index to what material slot each face should be assigned to. Running this code:

 i = 0
for poly in bpy.context.object.data.polygons:
poly.material_index = MyTextures[i]
i += 1


did the trick for what I needed it to do.

Now if I can only find the simple solution for assigning the UV's I will be almost done with my project.