# Assign Materials to specific faces in a mesh via Python

I have the following arrays (everything inside a structured array data):

Inside i have a struct called material, which has the following information:

face_start: The index of the first face that the material will be assigned

face_count: The amount of faces that material will be assigned to.

So for example: If face_start is 5, and face_count is 3, the code should assigned the faces 5, 6 and 7.

However it does not seem to apply, which i think it's an issue with the API and i can't seem to figure out properly how to assign said materials to the specific faces.

This is how i am attempting to assign said faces:

bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
#This is to set select mode to faces
bpy.context.tool_settings.mesh_select_mode = [False, False, True]

for j in range(len(data[i].materials)):
#Here i create a material, for example:
mat = bpy.data.materials.new(data[i].name + " Material" + str(j))
obj.data.materials.append(mat)
#After assigning all the material stuff, i proceed to assign it to the specific faces.
obj.active_material_index = j #I assign the recently added material as the active one
#I make a for loop where k is the first index (face_start) and goes to face_start + face_count, so it goes from face X to face X+Y
for k in range(data[i].material.face_start[j], data[i].material.face_start[j] + data[i].material.face_count[j]):
#I tried both of this, individually and at the same time, but none of them seem to work.
face_list[k].material_index = j
face_list[k].select = True
#This should assign the materials to all the faces where select = True, but it doesn't seem to
bpy.ops.object.material_slot_assign()
#I deselect everything so the selected faces are not there in the next loop
bpy.ops.mesh.select_all(action='DESELECT')


With changing things a little bit, i have achieved to either Assign all the faces to the very first material (aka probably nothing has been done), or it assigns all the the very last. But there doesn't seem to be an inbetween.

I'm probably not understanding the API properly, or there's something that i'm missing, but i'm a bit confused as of how to make it work to assign it to specific faces in a loop. What could i do in this scenario?

• Could you please make this a run-able example with data for the default cube. May 14 at 7:22

Based on your description of desired effects I've put together a couple small examples of how you may want to approach this.

You didn't really show what your materials should be or how you have them setup in your data structure so I provided a simple function to make basic materials around a hue wheel.

The other 2 functions will either evenly distribute materials to the faces of an object or as you described given a face start and run length of faces apply a specific material index to those faces.

You need to have all the materials you want to apply to an object's faces assigned to the object, then you can assign the material_index.

import bpy
import colorsys

num_colors = 3
repeat_color = 2
face_idx = 2
runlength = 4
mat_idx = 2
obj = bpy.context.object

def make_mats(obj, num_colors):
hsv=[]
for i in range(num_colors):
hue = i/num_colors
sat = 1
val = 1
hsv.append((hue, sat, val))
# clear current materials
while len(obj.material_slots) > 0:
bpy.ops.object.material_slot_remove()
for col in hsv:
if f'{obj.name}_{col[0]}' not in bpy.data.materials:
mat = bpy.data.materials.new(f'{obj.name}_{str(col[0])}')
r,g,b = colorsys.hsv_to_rgb(col[0], col[1], col[2])
mat.diffuse_color = (r,g,b,1)
else:
mat = bpy.data.materials[f'{obj.name}_{str(col[0])}']
bpy.context.object.data.materials.append(mat)

def assign_mats_even_dist(obj, repeat_color):
for i, face in enumerate(obj.data.polygons):
face.material_index = i // (repeat_color))%(len(obj.material_slots)

def assign_mats_idx_runlength(obj, face_idx, runlength, mat_idx):
if mat_idx > len(obj.material_slots)-1:
return {'CANCELLED'}
faces = [f for f in obj.data.polygons if f.index >= face_idx and f.index < face_idx + runlength]
for face in faces:
face.material_index = mat_idx

make_mats(obj, num_colors)

#assign_mats_even_dist(obj, repeat_color)

assign_mats_idx_runlength(obj, face_idx, runlength, mat_idx)

• Thank you! My main issue was assigning the ID's in the same loop as i was adding the materials, after i did it separate and structured it like you did, it works very well now. Thank you so much! May 15 at 0:09