I have a sphere with various materials assigned to different faces. I want to animate it, so the materials get assigned to different faces while the animation is running. Of course, I could always create a different material for each face manually and animate each one separately, but that is boring and repetitive. Is there any easy way to achieve this, maybe built-in or using AnimAll?
Two preliminary animations. Top with constant color. Lower with linear interpolated color. 2 Samples [only] per frame with Cycles, thus graininess. The OP can deliver more exact visual requirements.
import bpy import datetime print(datetime.datetime.today()) def object_id_mark(): m = 0 for s in bpy.context.selected_objects: m = m + 1 s.pass_index = m object_id_mark()
In the Python above, the object index is assigned values to coordinate with the materials nodes. Those objects are the faces of a sphere with a parent for grouping. Extrude Individual Faces and Separate Spare Parts. Those objects have the same parent. They can be easily selected and the script above is executed.
Material Nodes, note the group. Image above.
Detail of Group. Image above.
Material Nodes. The color ramp interpolation can be set to constant or linear. Click to see larger image.
Correct RNA path. Image above.
Be especially careful on the node named [Datablock Careful]. This value is the current frame in a material node which requires Datablock Driver. The 3 Panels are intended to stress the necessity of navigating a deep heirarchy in the Data-Blocks Mode of the Outlner Window.
This list is quite long and my path may not meet exactly your reading of the path. Changing the value manually will verify you have correctly navigated the hierarchy. The Outliner Data-Blocks window interface may help you reduce clicks by automatically opening a single choice when present.
Just to look at a different way of doing this, I thought I would use
bpy.app.handlers to do the material changes.
If we were starting from an empty scene we can create the sphere and a material with a random colour for each face.
import bpy import random bpy.ops.mesh.primitive_uv_sphere_add(segments=12, ring_count=12, size=1, location=(0, 0, 0)) obj = bpy.context.active_object # clear any existing material slots while len(obj.material_slots): bpy.ops.object.material_slot_remove() # create a random coloured material for each face # adjust this number to have less materials if desired # eg for f in range(10): will only create 10 materials for f in range(len(obj.data.polygons)): mat = bpy.data.materials.new('randomColour') bpy.ops.object.material_slot_add() obj.material_slots[-1].material = mat r = random.random() g = random.random() b = random.random() # mat.diffuse_color is also used by cycles for viewport colour # and as a fallback if nodes are not active mat.diffuse_color.r = r mat.diffuse_color.g = g mat.diffuse_color.b = b
Now that we have a material for each face, lets make a way to randomise what material each face uses.
import bpy import random def randomise_materials(scene): obj = scene.objects['Sphere'] polys = obj.data.polygons if scene.frame_current == 1: # by setting a seed on frame 1 we can get # a repeatable sequence during playback random.seed(5) m_idx =  i = 0 for x in range(len(polys)): # we want a list matching the number of faces # it can only contain indexes matching available materials if i >= len(obj.material_slots): i = 0 m_idx.append(i) i += 1 # after creating a list of indexes we can shuffle them # and then copy to the matching poly.material_index random.shuffle(m_idx) for i,p in enumerate(polys): p.material_index = m_idx[i] # set materials on first run randomise_materials(bpy.context.scene)
Then to use this for an animation we append this function to the handlers list.
And if you want to disable it