I would like to change polygon material during an animation with the following code. However, the animation does not show the color changes of the polygons. What is going wrong, isn't it possible to animate polygon material changes? What is the best solution to do it with Python?

frame_count = 1

for polygon in polygons:

    polygon.material_index = 1
    polygon.keyframe_insert(data_path='material_index', index = -1)
    frame_count += 10
  • $\begingroup$ Hello, could you add more information about what your code snippet is supposed to achieve ? Currently, you are trying to add a single keyframe per polygon at a 10 frame interval between each polygon until there is no more polygon left to iterate $\endgroup$
    – Gorgious
    Commented Jun 22, 2020 at 14:31
  • $\begingroup$ We have a path over a surface, every polygon of the surface that we visited should change its color. We are using to visualize some software algorithms on surfaces. $\endgroup$
    – Mirko
    Commented Jun 22, 2020 at 16:02

1 Answer 1


Random keyframing polygon material indices

enter image description here Code below run on a default cone with 4 materials of colour: red, green, blue, yellow.

  • Can set the frame in keyframe insert

  • All polygons are given material index 0 at frame 1

  • At the frame 2 times the polygon index plus 10 the polygon changes to a random choice of material slots with material.

Example script.

import bpy
from random import choice
context = bpy.context
ob = context.object
me = ob.data

choices = [i for i, s in enumerate(ob.material_slots)
        if s.material]
for p in me.polygons:
    p.material_index = 0
    p.keyframe_insert("material_index", frame=1)
    p.material_index = choice(choices)
    p.keyframe_insert("material_index", frame=2 * p.index + 10)

Using Drivers

enter image description here

It is a low level version of dynamic painting

In which case here is an example of using a driver instead of keyframing an fcurve.

Example below selects face index based on integer global distance of face center to emtpy. Have left in test driver method with test prints

The world matrices of the empty and the mesh object are added as driver variables, and passed to driver method by way of locals.

The image above is on a 16 x 16 grid, takes a while to run. On my system a 100 x 100 grid works but takes a while and can get unresponsive.

Select the mesh object and run script.

import bpy

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

mt = context.object

def add_driver(face):
    fcurve = face.driver_add("material_index")
    driver = fcurve.driver
    driver.use_self = True
    driver.expression = "x(self, locals())"
    var = driver.variables.new()
    var.name = "mw"
    var.targets[0].id = ob
    var.targets[0].data_path = "matrix_world"
    var = driver.variables.new()    
    var.name = "emw"    
    var.targets[0].id = mt
    var.targets[0].data_path = "matrix_world"
def x(self, locals):
    mw = locals["mw"]
    emw = locals["emw"]
    d = (mw @ self.center - emw.translation).length
    return min(int(d), 5)

bpy.app.driver_namespace["x"] = x

for p in me.polygons:


This one randomly sets color of faces of a modified (eg subsurf) mesh using a frame change handler.


  • $\begingroup$ @Mirko cheers. Have never ever seen, nor tried this.. thanks for the heads up! Opens numerous possibilities. $\endgroup$
    – batFINGER
    Commented Jun 22, 2020 at 18:41
  • $\begingroup$ it is a low level version of dynamic painting and very handy, thanks for your support $\endgroup$
    – Mirko
    Commented Jun 23, 2020 at 6:42

You must log in to answer this question.

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