2
$\begingroup$

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?

$\endgroup$
  • $\begingroup$ What is the desired end result? Because if you just want to change the color you can have one multicolored texture and animate it using the Hue/Saturation/Value Node's Hue slider to cycle through the color wheel. $\endgroup$ – Mentalist May 22 '16 at 18:17
  • $\begingroup$ How many faces? How many colors? How many frames before a color change. How much randomness? Cycles Render. Blender Internal Render. $\endgroup$ – atomicbezierslinger May 22 '16 at 18:25
  • $\begingroup$ Needs more info. Probably need to rethink the material itself rather than change materials. $\endgroup$ – kheetor May 23 '16 at 7:19
3
$\begingroup$

enter image description here

enter image description here

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.

enter image description here

Material Nodes, note the group. Image above.

enter image description here

Detail of Group. Image above.

Material Nodes. The color ramp interpolation can be set to constant or linear. Click to see larger image.

enter image description here

Correct RNA path. Image above.

enter image description here

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.

ObjectName/MaterialSlots/[MaterialName]/Material/[MaterialName]/NodeTree/ShaderNodes/[NodeName]

then

Outputs/Value/Node/[NodeName]/DefaultValue

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.

Image Above.

$\endgroup$
0
$\begingroup$

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.

bpy.app.handlers.frame_change_pre.append(randomise_materials)

And if you want to disable it

bpy.app.handlers.frame_change_pre.remove(randomise_materials)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.