Skip to content

Headless Rendering

In certain scenarios you might want to render with renderset from the console, without clicking on anything in the GUI. This is especially useful when rendering on a render farm.

Set up your render contexts

Make sure you set up your render context in the .blend files and File → Save before running these scripts. The scripts will start a fresh Blender and open the files. You will not be able to change the number of samples, camera resolution, or any other render setting after running these scripts!

We assume all data are in place

All the data necessary for the render have to be in place. Please check out the docs about render farms for more details on how to achieve this.

Windows

cmd.exe box

Other shells work too

You can use mingw bash, powershell or others but we will use cmd.exe here.

Press Win+R and type cmd.exe. You should see a black terminal box appear.

cmd.exe navigate to blender.exe

Use terminal commands to navigate to where your Blender is installed. In my case it is C:/blender-4.2-windows-x64:

cd C:/
cd blender-4.2-windows-x64
dir

If you typed blender.exe here it would just start Blender with GUI. We have to use some special command-line switches and arguments to make it run without GUI. You can see all the command-line possibilities by typing blender.exe --help and pressing Enter.

Render Single Context

Before we do that let us create a little script that will render via renderset when blender is running headless. We recommend creating it in the same folder where your Blender is installed. It makes the command-line options easier. In my case it is going to be C:/blender-4.2-windows-x64/renderset_render_current.py. Create that file and copy the following into it:

renderset_render_current.py
#!/usr/bin/python3

import bpy

rset_context_index = bpy.context.scene.renderset_context_index
rset_context = bpy.context.scene.renderset_contexts[rset_context_index]
# we need this handler to move data to the final output dir
bpy.app.handlers.render_post.append(
    lambda scene, dummy: rset_context.render_finished(scene))

output_folders = rset_context.render(bpy.context)
# If you don't want to execute post render actions after rendering:
# rset_context.render(bpy.context, execute_post_render_actions=False)
bpy.app.handlers.render_post.clear()

print(f"Context rendered to: {output_folders}")

Let us now start blender.exe and tell it to run without GUI and execute the script we just created.

blender.exe --background --python renderset_render_current.py

Blender should run for a bit and then output the following: cmd.exe default cube render

Oh no! We rendered the default cube because no .blend file was opened. Let us fix that:

blender.exe --background C:/Users/Martin/Desktop/test.blend --python renderset_render_current.py

Order of arguments matters!

Make sure you input the command line arguments in the right order! Otherwise Blender will run the renderset code and then open the .blend file.

cmd.exe test blend render

Render All Checked Contexts

We were able to render the current active context in the previous section. How do we render all contexts? We need a different script. Let us call this one renderset_render_all.py. Create it and put the following code there:

renderset_render_all.py
#!/usr/bin/python3

import bpy
import datetime

# we will save all the final paths to this list
render_output_paths = set()
time = datetime.datetime.now()
for rset_context_index in range(len(bpy.context.scene.renderset_contexts)):
    bpy.context.scene.renderset_context_index = rset_context_index
    rset_context = bpy.context.scene.renderset_contexts[rset_context_index]
    if not rset_context.include_in_render_all:
        # skip render contexts with unchecked checkbox
        continue
    # we need this handler to move data to the final output dir
    bpy.app.handlers.render_post.append(
        lambda scene, dummy: rset_context.render_finished(scene))

    # If you do not use the time argument, time-related variables will expand to different
    # timestamps for each context
    output_folders = rset_context.render(bpy.context, time=time)
    # If you don't want to execute post render actions after rendering:
    # rset_context.render(bpy.context, execute_post_render_actions=False, time=time)
    bpy.app.handlers.render_post.clear()
    render_output_paths = render_output_paths.union(output_folders)

for path in render_output_paths:
    print(f"Context rendered to: {path}")

And run:

blender.exe --background C:/Users/Martin/Desktop/test.blend --python renderset_render_all.py

You should get this output: cmd.exe test blend render all

Render All Checked Contexts in Multiple Files

We were able to render all contexts in a single file in the previous section. Now we will expand it to rendering many files. Again, we need a slightly different script. Let us call this one renderset_render_all_multiple_files.py. Create it and put the following code there:

renderset_render_all_multiple_files.py
#!/usr/bin/python3

import bpy
import glob
import os
import datetime

def render_all():
    # we will save all the final paths to this list
    render_output_paths = set()
    time = datetime.datetime.now()
    for rset_context_index in range(len(bpy.context.scene.renderset_contexts)):
        bpy.context.scene.renderset_context_index = rset_context_index
        rset_context = bpy.context.scene.renderset_contexts[rset_context_index]
        if not rset_context.include_in_render_all:
            # skip render contexts with unchecked checkbox
            continue
        # we need this handler to move data to the final output dir
        bpy.app.handlers.render_post.append(
            lambda scene, dummy: rset_context.render_finished(scene))

        # If you do not use the time argument, time-related variables will expand to different
        # timestamps for each context
        output_folders = rset_context.render(bpy.context, time=time)
        # If you don't want to execute post render actions after rendering:
        # rset_context.render(bpy.context, execute_post_render_actions=False, time=time)
        bpy.app.handlers.render_post.clear()
        render_output_paths = render_output_paths.union(output_folders)

    return {os.path.abspath(bpy.data.filepath): render_output_paths}


# TODO: PUT THE RIGHT FILEPATH BELOW BETWEEN THE QUOTES
files = glob.glob("C:/Users/Martin/Desktop/files_to_render/*.blend")

# You can also specify the files in a list:
#files = [
#    "C:/Users/Martin/Desktop/files_to_render/file1.blend",
#    "C:/Users/Martin/Desktop/files_to_render/file2.blend",
#]

all_results = {}
for file_ in files:  # for each file we specified
    bpy.ops.wm.open_mainfile(filepath=file_)  # open the file
    all_results = {
        **all_results,
        **render_all()  # and render all checked contexts
    }

for blend_path, render_results in all_results.items():
    print(f"{blend_path} produced: ")
    for render_result in render_results:
        print(f"- {render_result}")
    print("")

Before running the command make sure you change the filepath in the script. Find the line with TODO.

And run:

blender.exe --background --python renderset_render_all_multiple_files.py

Tip

Note that this time we are not telling blender.exe to open any files, the script itself will do that.

Write One Blend per Context

For some use cases you cannot use renderset at the machine doing the rendering. For example when rendering on a farm that will not let you run any python on it. If you have a .blend file with several contexts you may want to split it and render the individual separate blend files. This can be achieved by writing a simple script, let us call this script renderset_split_by_context.py. Create it and put the following code there:

renderset_split_by_context.py
#!/usr/bin/python3

import bpy
import os

opened_basename, ext = os.path.splitext(bpy.data.filepath)
assert ext == ".blend"

for rset_context_index in range(len(bpy.context.scene.renderset_contexts)):
    bpy.context.scene.renderset_context_index = rset_context_index
    rset_context = bpy.context.scene.renderset_contexts[rset_context_index]
    if not rset_context.include_in_render_all:
        # skip render contexts with unchecked checkbox
        continue

    bpy.context.scene.renderset_context_index = rset_context_index
    bpy.ops.wm.save_as_mainfile(filepath=f"{opened_basename}_{rset_context_index}{ext}")

And run:

blender.exe --background C:/Users/Martin/Desktop/test.blend --python renderset_split_by_context.py

macOS 10

Sorry, work in progress. Instructions from the Windows section should work with minor path and syntax modifications.

Linux

Sorry, work in progress. Instructions from the Windows section should work with minor path and syntax modifications.