First Steps with Python and Blender

I recently started playing with Blender again and wanted to try out animating a scene using Python scripts. This tutorial summarizes what I learned and should give bloody beginners a few pointers in the right direction.

In this tutorial you will learn how to add to a scenes content programatically, how to update the objects you created and how to render the output into a video. If you want to skip the write-up feel free to go straight to the .blend file on my Github account.

The basics

Blenders python bindings are available through the blenderpy module. This module contains everything we need to interact with Blender from Python. Blender itself contains a moderately comfortable text editor for accessing and editing Python files embedded in a .blend file. It is available through the scripting view (in a line with Layout / Modeling / Shading etc.).

Since the animation we are building here depends on trigonometric functions we also import Pythons math module.

import bpy
import math

scn = bpy.context.scene

The scene object constructed in the third line represents the visual scene that will contain the objects.

Building the Scene

For this scene we will build and animate a grid of cubes. Not all steps will be done programatically, since building the material shader is way more comfortable through Blenders node editor.

def remove_cubes() -> None:
    for ob in bpy.context.scene.objects:
        ob.select_set(ob.name.startswith("Cube"))
    bpy.ops.object.delete()
    
def populate() -> None:
    for x_ind in range(0, count):
        for y_ind in range(0, count):
            print("init", x_ind, y_ind)
            x = x_ind / count
            y = y_ind / count
            z = 0
            bpy.ops.mesh.primitive_cube_add(location=(x - 0.5, y - 0.5, z), scale=(ob_size, ob_size, ob_size))
            bpy.context.active_object.data.materials.append(mat)

These two functions initialize the scene be removing all cube objects and then adding new ones to a grid with parametric size.
Note that the remove cubes function removes objects by name and ignores all objects that are not cubes, such as the scenes camera or lights.

Animating the Scene

def update_cubes() -> None:
    for ob in bpy.context.scene.objects:
        if ob.name.startswith("Cube"):
            x = ob.location[0]
            y = ob.location[1]
            z = amplitude * math.sin(t + freq * x / count) * math.cos(t + freq * y / count)
            ob.location[2] = z   

[...]

for i in range(0, steps):
    t += dt
    print("step", t)
    update_cubes()
    scn.render.filepath = '/tmp/' + str(i)
    bpy.ops.render.render(write_still=True)

Within the animation process first the current time is increased by a fixed step, then update function is called and finally a new image is rendered. These steps are repeated until the step count is reached.
Inside the update function the cubes z position is adjusted according to the amplitude of an overlapping sine and cosine function.
Running the script will result in a series of images using a step index as filename. This series of images can be converted to a video using a tool such as ffmpeg:

ffmpeg -stream_loop 3 -i %d.png out.mp4

I like using FFmpeg instead of Blenders video tools, since the command line options give fine control over the output options as repetition (stream_loop), compression, framerate and alike. However adopting the script to use direct video encoding is straight forward.

Using these steps and the .blend file from Github you should be able to create your first animation using Python and Blender.