Blender Headless Integration
The Blender integration lets you drive Blender entirely from a Vibrante-Node graph — opening .blend files, configuring render settings, rendering animation sequences, exporting geometry in any supported format, running custom Blender Python scripts, and more — all without ever opening the Blender UI. Vibrante-Node launches Blender as a headless subprocess (blender --background) and passes it a compiled action list that a bundled runner script processes sequentially inside the Blender Python context.
The integration ships 21 Blender nodes in the Blender category and follows the same action-list architecture as the Maya Headless integration: individual blender_action_* nodes build up a list of operation dictionaries, and the blender_headless executor node launches Blender and processes them all in one subprocess invocation.
How It Works
The Action-List Pattern
No Blender node performs work directly inside Vibrante-Node. Instead, each blender_action_* node appends a plain Python dictionary — an action descriptor — to a list that flows through the graph. When the blender_headless executor node fires, it serialises the entire list to JSON and passes it to a Blender runner script via blender --background --python runner.py -- <json_path>. The runner script reads the JSON, iterates through the actions, and dispatches each one to its handler using Blender's Python API (bpy).
This design keeps Vibrante-Node itself free of any Blender dependency. Blender does not need to be importable as a Python module — it only needs to be a callable executable on the system PATH or at a configured path.
Architecture Diagram
Vibrante-Node Graph Blender Subprocess
─────────────────── ──────────────────
blender_action_open ─┐ blender --background
blender_action_set_render ├─ list─► runner.py
blender_action_render ┘ processes actions
blender_action_export_gltf sequentially
│
blender_headless ──────────────► subprocess.Popen(["blender", "--background", ...])
Exec Flow vs. Data Flow
Two parallel wire chains connect the nodes in a typical Blender graph:
- Data chain —
actions_out→actions_inpasses the growing action list from node to node. - Exec chain —
exec_out→exec_incontrols the order of execution inside Vibrante-Node's engine.
Both chains must be wired. The exec chain determines when each node runs; the data chain determines what goes into the final action list.
Node Skeleton
All Blender action nodes share the same structure. Here is the blender_action_open node as a reference implementation:
class Blender_Action_Open(BaseNode):
name = "blender_action_open"
def __init__(self):
super().__init__()
# [AUTO-GENERATED-PORTS-START]
self.add_input("actions_in", "list")
self.add_input("blend_file", "string", widget_type="text")
self.add_output("actions_out", "list")
# [AUTO-GENERATED-PORTS-END]
async def execute(self, inputs):
actions = list(inputs.get("actions_in") or [])
actions.append({
"type": "open",
"blend_file": inputs.get("blend_file", "")
})
return {"actions_out": actions, "exec_out": True}
def register_node():
return Blender_Action_Open
Key conventions that every action node must follow:
actions_inandactions_outare mandatory — they form the data chain.- Always initialise the list with
list(inputs.get("actions_in") or []). This avoids mutating the upstream list in place and handles the case whereactions_inisNone(the first node in a chain). - The
"type"key in the action dictionary must exactly match a handler registered in the Blender runner script. node_idfollows theblender_action_*naming convention.icon_pathis"icons/blender.svg".
Node Library
The integration ships 21 nodes across several functional groups.
Scene Management
| Node ID | Description |
|---|---|
blender_action_open | Open an existing .blend file. |
blender_action_clean_scene | Remove all objects from the current scene (useful before importing assets). |
blender_action_save | Save the current scene to a .blend file at a specified path. |
blender_action_run_script | Execute an arbitrary Python script inside the Blender context. The script has full access to bpy. |
Rendering
| Node ID | Description |
|---|---|
blender_action_render | Render a frame range to an output directory. |
blender_action_set_render_engine | Set the render engine (e.g. CYCLES, BLENDER_EEVEE). |
blender_action_set_output_dir | Set the render output directory path. |
blender_action_set_frame_range | Set the scene start and end frame. |
blender_action_set_resolution | Set the render resolution (width, height, percentage). |
blender_action_bake | Bake a specified texture type (AO, normals, diffuse, etc.) for the selected objects. |
Import / Export
| Node ID | Description |
|---|---|
blender_action_export_fbx | Export scene or selection to FBX. |
blender_action_export_obj | Export scene or selection to OBJ + MTL. |
blender_action_export_gltf | Export scene or selection to glTF 2.0 (binary .glb or text .gltf). |
blender_action_export_usd | Export scene to USD (Universal Scene Description). |
blender_action_import_fbx | Import an FBX file into the current scene. |
blender_action_import_obj | Import an OBJ file into the current scene. |
Geometry & Materials
| Node ID | Description |
|---|---|
blender_action_apply_modifier | Apply a named modifier (e.g. Subdivision, Decimate) to a named object. |
blender_action_join_objects | Join a list of named objects into a single mesh. |
blender_action_separate_objects | Separate a mesh by loose parts or material. |
blender_action_set_material | Assign a named material to a named object (material must exist in the blend file or be created by a prior script action). |
Executor Node
| Node ID | Description |
|---|---|
blender_headless | Launches blender --background, passes the accumulated action list to the runner script, and waits for completion. Outputs success (bool) and log_output (string). |
Complete Workflow Example
The following example builds a complete render-and-export pipeline: open a character asset, render the animation, and export as glTF for use in a game engine or web viewer. Paste this into the Scripting Console (Window → Scripting Console) to build the graph programmatically.
scene.clear()
open_node = scene.add_node_by_name("blender_action_open", (0, 0))
open_node.set_parameter("blend_file", "C:/assets/character.blend")
render_node = scene.add_node_by_name("blender_action_render", (300, 0))
render_node.set_parameter("output_dir", "C:/renders/character/")
render_node.set_parameter("start_frame", 1)
render_node.set_parameter("end_frame", 250)
export_node = scene.add_node_by_name("blender_action_export_gltf", (600, 0))
export_node.set_parameter("output_path", "C:/exports/character.glb")
exec_node = scene.add_node_by_name("blender_headless", (900, 0))
# Data chain
scene.connect_nodes(open_node, "actions_out", render_node, "actions_in")
scene.connect_nodes(render_node, "actions_out", export_node, "actions_in")
scene.connect_nodes(export_node, "actions_out", exec_node, "actions_in")
# Exec chain
scene.connect_nodes(open_node, "exec_out", render_node, "exec_in")
scene.connect_nodes(render_node, "exec_out", export_node, "exec_in")
scene.connect_nodes(export_node, "exec_out", exec_node, "exec_in")
app.execute_pipeline()
Configuration
Blender Executable Path
By default, the blender_headless executor looks for blender on the system PATH. On Windows, Blender is typically not added to PATH automatically during installation. Configure the path explicitly via Settings → Environment Variables in the Vibrante-Node preferences dialog (Edit → Preferences…):
| Variable | Example Value | Description |
|---|---|---|
BLENDER_EXECUTABLE | C:/Program Files/Blender Foundation/Blender 4.1/blender.exe | Full path to the Blender executable. |
BLENDER_RUNNER_SCRIPT | (auto-detected) | Path to the Blender runner Python script. Defaults to the bundled script; override if using a custom runner. |
You can have multiple Blender versions installed and select which one to use per-project by setting BLENDER_EXECUTABLE in the Environment Variables page. This is useful when targeting different rendering pipelines (Blender 3.x Cycles vs Blender 4.x EEVEE Next).
Runner Script
The bundled runner script lives at plugins/blender/blender_runner.py inside the application directory. It is passed to Blender via blender --background --python blender_runner.py -- /tmp/actions_xxxxxxxx.json. The runner script:
- Reads the JSON action list from the path passed as the first positional argument after
--. - Iterates through actions in order.
- Dispatches each action's
"type"key to the corresponding handler function. - Writes a result JSON to stdout on completion (success or error per action).
If you need to add custom action types, create your own runner script that imports and extends the bundled one, and point BLENDER_RUNNER_SCRIPT to it.
Action Type Reference
The "type" field in every action dictionary must match exactly one of the following registered handler identifiers:
| type string | Required fields | Optional fields |
|---|---|---|
open | blend_file | — |
save | output_path | — |
clean_scene | — | — |
render | output_dir | start_frame, end_frame, file_format |
set_render_engine | engine | — |
set_output_dir | output_dir | — |
set_frame_range | start_frame, end_frame | — |
set_resolution | width, height | percentage |
export_fbx | output_path | use_selection, apply_modifiers |
export_obj | output_path | use_selection |
export_gltf | output_path | export_format (GLB/GLTF_SEPARATE), use_selection |
export_usd | output_path | export_textures |
import_fbx | file_path | — |
import_obj | file_path | — |
run_script | script_path | script_args (dict) |
apply_modifier | object_name, modifier_name | — |
join_objects | object_names (list) | result_name |
separate_objects | object_name | mode (LOOSE/MATERIAL) |
set_material | object_name, material_name | — |
bake | bake_type, output_path | object_name, image_size |
Production Use Cases
Game Asset Pipeline
Import FBX assets exported from Maya, apply a Decimate modifier to reduce polygon count, and re-export as glTF for use in a game engine or real-time web viewer — all fully automated and reproducible.
actions = []
# Import Maya export
actions.append({"type": "import_fbx", "file_path": "/exports/maya/hero_rig.fbx"})
# Reduce polycount for LOD1
actions.append({"type": "apply_modifier", "object_name": "hero_body", "modifier_name": "Decimate"})
# Export for web
actions.append({"type": "export_gltf", "output_path": "/web/assets/hero_lod1.glb",
"export_format": "GLB", "use_selection": False})
Batch Render Farm Preparation
For each shot in a sequence, open the corresponding blend file, set the render engine and output path, configure the frame range from a Prism Pipeline query, save the prepared scene, and submit it to Deadline — all in a single Vibrante-Node graph execution.
Format Conversion Pipeline
Convert an entire library of .blend files to USD for a multi-DCC pipeline where downstream tools (Houdini, Karma, USD Hydra) consume USD natively. Loop over files using a for_each control node and chain a blender_action_open → blender_action_export_usd → blender_headless subgraph.
Procedural Scene Population
Use blender_action_run_script to invoke custom bpy scripts that scatter instanced objects across a terrain, assign randomised materials, or bake lightmaps — keeping complex procedural logic inside Blender while orchestrating the overall pipeline from Vibrante-Node.
Automated LOD Generation
Run a Blender Python script via blender_action_run_script that iterates over all mesh objects, applies a Decimate modifier with a configurable ratio, and exports separate LOD levels as FBX. Wire this into a Maya headless pre-processing step that exports the source geometry, passing the file path through the graph as a string data pin.
Troubleshooting
Blender executable not found
If blender_headless reports FileNotFoundError or blender: command not found, set BLENDER_EXECUTABLE to the full path in Settings → Environment Variables and restart the application (or use Scripts → Refresh Scripts to reload the environment without restarting).
Runner script errors
Errors inside the Blender subprocess are captured and surfaced in the Vibrante-Node log panel as part of the log_output from the blender_headless node. Check for Python tracebacks in the log — they will reference the runner script and the specific action that failed.
Unknown action type
If the runner reports Unknown action type: 'my_type', verify the "type" string in your action dictionary matches the handler name exactly (case-sensitive). Check the action type reference table above.
Blender's Python API (bpy) is only available inside the Blender subprocess — it cannot be imported in Vibrante-Node's own Python environment. Never attempt to import bpy in a node's execute() method. Use blender_action_run_script to run bpy code inside the Blender context.