# How to change the texture of an object after a few frames? [closed]

So my question is that I want to change the texture of the object after a few frames. For example, after every 100 frames, the texture changes to the next texture. I have this little bit of code, so can you please.

import bpy

D = bpy.data

D.objects['Cube'].material_slots[0].material = D.materials['Material.001']


BTW, I am using blender 2.83.

• Objects don't have textures, materials do. Also your code is apparently attempting to assign materials to slots, there doesn't seem to be any code dealing with textures. Could you clarify what you are trying to achieve? Apr 7 '21 at 15:46
• I don't have a complete answer (setting a key) but for changing materials I would use a mix shader and key the Factor from 0 to 1, as in bpy.data.materials["Material1"].node_tree.nodes["Mix Shader"].inputs[0].default_value = 0 . How to set the "key" for these changes... uhm... Apr 7 '21 at 19:17
• Besides previous comment, there may also be a way to subscribe to a frame-change message and set the material accordingly. Apr 7 '21 at 19:21

I had time and interest to conjure up an example python script that may do what you're looking for: to reassign a material based on a frame change. It uses a call-back Handler that subscribes to frame changes and applies a different material when it detects a frame # boundary change. You'd want to enhance this perhaps with a list of frame changes and Material names in two lists, for multiple materials.

This assume objects['Cube'], and materials['Material.001'] and materials['Material.002']

The file contains the script and demo object and materials (plus an extra animated sphere). Note that I also incorporated @MarkusvonBroady's Group technique as an example applied to the Sphere object as Material.003.

import bpy

matlID=0

# this handler will is set up to be called with the "handlers.frame_change_pre" callback for every frame change
def frame_change_handler( scene ):
global matlID
print( "frame=", bpy.context.scene.frame_current )
currFrame = bpy.context.scene.frame_current
print(matlID)
if ( (currFrame >= 10) and (matlID!=2) ):
print("change to Material.002")
D.objects['Cube'].material_slots[0].material = bpy.data.materials['Material.002']
matlID=2
if ( (currFrame < 10) and (matlID!=1) ):
print("change to Material.001")
D.objects['Cube'].material_slots[0].material = bpy.data.materials['Material.001']
matlID=1

D = bpy.data
# initialize to first material
D.objects['Cube'].material_slots[0].material = D.materials['Material.001']
matlID=1
for m in D.materials:
print(m)

bpy.app.handlers.frame_change_pre.clear()

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

print( "frame_change being tracked" )
$$$$


for "changing materials" I might use a mix shader in a single material and key the Factor between 0 and 1, with animation. As you'll see in the screencap, the factor is in color showing that it was animated (by the following script)

It's important to notice that when you add Mix Shaders, they are not referenced by the (re)name you give them but appear to be "Mix Shader", "Mix Shader.001", "Mix Shader.002" and so on.

Per @MarkusvonBroady's comment below, you can also use Node Groups to mix "Material Outputs", to better organize what could become an unwieldly number of nodes in a single Material definition. Here is the file.


for node in bpy.data.materials["MyMatl with mixer"].node_tree.nodes:
print(node)

• @Aster17 you can chain mix nodes like so: i.imgur.com/yIAwlB9.png the drivers are simply #frame > 10, #frame > 20, #frame > 30` which mean the first texture will display at the beginning and be switched to 2nd on frame 10, which will be switched to 3rd on frame 20 which will be switched to 4th on frame 30. You should be fine doing that for 10 textures. Fore more textures consider an automated script to generate the material or a custom node like here: blender.stackexchange.com/questions/67487/… Apr 10 '21 at 0:09