Baking Textures as Image Sequence by Script in Cycles Related to this: Baking textures on headless machine (batch baking)

Is there a way to batch the baking of textures over all frames? I have an animation and since the light is changing at each frame, would like to bake out the texture of each frame into an image sequence.


I've set my render mode to cycles
I've added a Image Texture Node and have it set to image sequence
My UV is unwrapped to the image sequence


If I put this in console, I can bake one frame to the sequence:

bpy.data.objects["Cube"].select = True
bpy.context.scene.frame_current = 1
bpy.ops.object.bake(type='COMBINED')


Similarly, I can bake another frame:

bpy.data.objects["Cube"].select = True
bpy.context.scene.frame_current = 2
bpy.ops.object.bake(type='COMBINED')


However, when I try to put this in a for loop to bake multiple frames like this:

for i in range(1,30):
     bpy.context.scene.frame_current = i
     bpy.data.objects["Cube"].select = True
     bpy.ops.object.bake(type='COMBINED')


It will only bake the texture of the first frame in the loop. It appears like it is looping through all the frames and it is baking them, but the images in those frames do not get updated once the script is finished. Any ideas on what is happening?
Since 'Animation Baking' is now officially supported by this Add-on (shipped with Blender by default), you can simply call bpy.ops.object.anim_bake_image() for a sequence:

import bpy

scn = bpy.context.scene
scn.animrenderbake_start = 3
scn.animrenderbake_end = 30
bpy.ops.object.anim_bake_image('INVOKE_DEFAULT')


The following script is a slightly modified version of the Add-on in order to bake specific frames (for demonstration purposes). To bake all frames (or a custom range) use the range() function.

import bpy
import os
import shutil

# set the frames to bake
bake_frames = [0, 230, 99]

# format frame number
def framefile(filepath, frame):
    fn, ext = os.path.splitext(filepath)
    return "%s_%04d%s" % (fn, frame, ext)

# scene attributes
context = bpy.context
is_cycles = (context.scene.render.engine == 'CYCLES')
selected = context.selected_objects
img = None

# inspect the materials
if is_cycles:
    inactive = None
    selected = None
    for mat_slot in context.active_object.material_slots:
        mat = mat_slot.material
        if not mat or not mat.node_tree:
            continue
        trees = [mat.node_tree]
        while trees and not img:
            tree = trees.pop()
            node = tree.nodes.active
            if node.type in {'TEX_IMAGE', 'TEX_ENVIRONMENT'}:
                img = node.image
                break
            for node in tree.nodes:
                if node.type in {'TEX_IMAGE', 'TEX_ENVIRONMENT'} and node.image:
                    if node.select:
                        if not selected:
                            selected = node
                    else:
                        if not inactive:
                            inactive = node
                elif node.type == 'GROUP':
                    trees.add(node.node_tree)
        if img:
            break
    if not img:
        if selected:
            img = selected.image
        elif inactive:
            img = inactive.image
else:
    for uvtex in context.active_object.data.uv_textures:
        if uvtex.active_render == True:
            for uvdata in uvtex.data:
                if uvdata.image is not None:
                    img = uvdata.image
                    break

# convert the path to absolute path
img_filepath_abs = bpy.path.abspath(img.filepath, library=img.library)

# iterate through the frame list
for f in bake_frames:
    print("Baking frame %d" % f)

    # set the frame
    context.scene.frame_set(f)

    # cycles bake 
    if is_cycles:
        bpy.ops.object.bake()

    # internal bake
    else:
        bpy.ops.object.bake_image()

    # save the image
    img.save()
    img_filepath_new = framefile(img_filepath_abs, f)

    # copy the image
    shutil.copyfile(img_filepath_abs, img_filepath_new)
    print("Saved %r" % img_filepath_new)