# Color individual faces after modifier

It is possible to color individual faces of a model by going to edit mode and assigning different textures to each face.

I'm using a low poly model to which I apply a subdivision modifier and subsequently a decimate modifier. When I go to edit mode I only see the faces of the original mesh. This does not map well with the final result and therefore I'm not able to color it appropriately. How could I color individual faces without applying the modifiers.

Once you use a Generate Modifier (decimate counts as well) you don't have much control over the mesh anymore. Since modifiers are by nature dynamic, you can't change individual faces, since they might not exist in another frame.
Usually you would use vertex paint in a situation like this, but that's also not easy.
One method to cheat I can think of right now is: Use a texture, unwrap your model and make the decimate modifier respect the seams. It's fiddly, but you might get this working.

• A bit unfortunate because the unavailability of the mesh make a couple of non destructive workflows quite hard. I've had other examples where I wanted to extrude a face after a modifier which is simply not possible. I think I'll just make a copy which I hide and apply the modifiers. – takje Jun 3 '20 at 21:06

I created a script to help with this:

import bpy
import bmesh
import random

def view_materials():
ob = bpy.context.object
assert ob is not None and ob.type == 'MESH', "active object invalid, select a mesh"
materials = ob.data.materials.items()
bpy.ops.object.mode_set(mode='EDIT')
mesh = bmesh.from_edit_mesh(ob.data)

indexes = [[face.index, face.material_index] for face in mesh.faces]
material_indexes = []
for index in indexes:
tuple = (index[0], materials[index[1]])
print(tuple)
material_indexes.append(tuple)
bpy.ops.object.mode_set(mode='OBJECT')

def make_random():
ob = bpy.context.object
assert ob is not None and ob.type == 'MESH', "active object invalid, select a mesh"
materials = ob.data.materials.items()
bpy.ops.object.mode_set(mode='EDIT')
mesh = bmesh.from_edit_mesh(ob.data)
for face in mesh.faces:
face.material_index = random.randrange (0, len(materials),1)
bpy.ops.object.mode_set(mode='OBJECT')

print('before')
view_materials()
print('making random')
make_random()
print('after')
view_materials()


Results:

    before
(0, ('Material', bpy.data.materials['Material']))
(1, ('Material', bpy.data.materials['Material']))
(2, ('Material', bpy.data.materials['Material']))
(3, ('Material', bpy.data.materials['Material']))
(4, ('Material', bpy.data.materials['Material']))
(5, ('Material', bpy.data.materials['Material']))
making random
after
(0, ('Material.003', bpy.data.materials['Material.003']))
(1, ('Material', bpy.data.materials['Material']))
(2, ('Material.003', bpy.data.materials['Material.003']))
(3, ('Material', bpy.data.materials['Material']))
(4, ('Material.001', bpy.data.materials['Material.001']))
(5, ('Material.002', bpy.data.materials['Material.002']))


Instructions for use: Create your color pallet by creating as many materials as you want in the materials. Select your object, then run this script. It will randomly choose a selection from the color pallet and put it on your cube or whatever.

• A issue here is a modifier like subsurf subdivides the faces of the original and displays the modified mesh. (eg Apply the default subsurf modifier to default cube and it will have 24 faces. The OP does not wish to apply the modifier. Your script only randomly colours the original 6 faces. – batFINGER Jun 20 '20 at 14:50

Frame change post handler

Note this answer popped up as a thought bubble wrt commenting on the other python answer re randomly colouring faces, It is possibly of little use to OP, depending on what kind of control is needed. As OP commented using an applied copy could also be a way to produce a map to color faces in handler.

Render result using handler script 2 levels of subsurf above, 4 below

As a proof of concept wondered whether changing the material indices on faces of the evaluated object of a modified mesh would work.

It does not show in the material preview but renders Ok.

The default cube with 4 materials and one level subsurf

Proof of concept script, randomly sets material index of each modified face for each frame.

import bpy
from random import choice

choices = list(range(4))

def random_col(scene, depsgraph):
cube = scene.objects.get("Cube")

cube_eval = cube.evaluated_get(depsgraph)
for f in cube_eval.data.polygons:
f.material_index = choice(choices)

# comment line below when finished testing
bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(random_col)


To instead set all faces material indices once would calculate the list outside handler, and use to set indices within handler.

Yes, it is.

Go from Object mode to Edit mode. (It's a pull down over a perspective view window)

Press the Face Select button (of the three icons in a row, vertex|Edge|Face select)

Left click on faces to select them (use shift to add more)

Go to the Materials editor, choose or make the material you want.

Press the "Assign" button to assign the material you have selected to the selected faces.

• Please read the question carefully. The OP is referring to faces created by a modifier. Using method above would require applying the modifier which the OP states they do not wish to do. – batFINGER Jun 23 '20 at 4:19