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
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.
Use terminal commands to navigate to where your Blender is installed. In my case it is
C:/blender-3.0-windows64
:
cd C:/
cd blender-3.0-windows64
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-3.0-windows64/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.render_set_context_index
rset_context = bpy.context.scene.render_set_contexts[rset_context_index]
# we need only this handler to move data to the final output dir
bpy.app.handlers.render_post.append(
lambda scene, dummy: rset_context.render_finished(bpy.context))
rset_context.render(bpy.context)
# if you want to override the final path you can use this method instead:
#rset_context.render(bpy.context, final_output_folder_path_override=output_folder)
print(f"Context rendered to: {rset_context.final_output_folder_path}")
|
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:
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.
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
# we will save all the final paths to this list
render_output_paths = []
for rset_context_index in range(len(bpy.context.scene.render_set_contexts)):
rset_context = bpy.context.scene.render_set_contexts[rset_context_index]
if not rset_context.include_in_render_all:
# skip render contexts with unchecked checkbox
continue
# we need only this handler to move data to the final output dir
bpy.app.handlers.render_post.append(
lambda scene, dummy: rset_context.render_finished(bpy.context))
rset_context.render(bpy.context)
bpy.app.handlers.render_post.clear()
render_output_paths.append(rset_context.final_output_folder_path)
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:
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
def render_all():
# we will save all the final paths to this list
render_output_paths = []
for rset_context_index in range(len(bpy.context.scene.render_set_contexts)):
rset_context = bpy.context.scene.render_set_contexts[rset_context_index]
if not rset_context.include_in_render_all:
# skip render contexts with unchecked checkbox
continue
# we need only this handler to move data to the final output dir
bpy.app.handlers.render_post.append(
lambda scene, dummy: rset_context.render_finished(bpy.context))
rset_context.render(bpy.context)
bpy.app.handlers.render_post.clear()
render_output_paths.append(rset_context.final_output_folder_path)
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.render_set_contexts)):
rset_context = bpy.context.scene.render_set_contexts[rset_context_index]
if not rset_context.include_in_render_all:
# skip render contexts with unchecked checkbox
continue
bpy.context.scene.render_set_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.