v2.2.1
🔍
✓ Verified — v2.2.1

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:

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:


Node Library

The integration ships 21 nodes across several functional groups.

Scene Management

Node IDDescription
blender_action_openOpen an existing .blend file.
blender_action_clean_sceneRemove all objects from the current scene (useful before importing assets).
blender_action_saveSave the current scene to a .blend file at a specified path.
blender_action_run_scriptExecute an arbitrary Python script inside the Blender context. The script has full access to bpy.

Rendering

Node IDDescription
blender_action_renderRender a frame range to an output directory.
blender_action_set_render_engineSet the render engine (e.g. CYCLES, BLENDER_EEVEE).
blender_action_set_output_dirSet the render output directory path.
blender_action_set_frame_rangeSet the scene start and end frame.
blender_action_set_resolutionSet the render resolution (width, height, percentage).
blender_action_bakeBake a specified texture type (AO, normals, diffuse, etc.) for the selected objects.

Import / Export

Node IDDescription
blender_action_export_fbxExport scene or selection to FBX.
blender_action_export_objExport scene or selection to OBJ + MTL.
blender_action_export_gltfExport scene or selection to glTF 2.0 (binary .glb or text .gltf).
blender_action_export_usdExport scene to USD (Universal Scene Description).
blender_action_import_fbxImport an FBX file into the current scene.
blender_action_import_objImport an OBJ file into the current scene.

Geometry & Materials

Node IDDescription
blender_action_apply_modifierApply a named modifier (e.g. Subdivision, Decimate) to a named object.
blender_action_join_objectsJoin a list of named objects into a single mesh.
blender_action_separate_objectsSeparate a mesh by loose parts or material.
blender_action_set_materialAssign 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 IDDescription
blender_headlessLaunches 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…):

VariableExample ValueDescription
BLENDER_EXECUTABLEC:/Program Files/Blender Foundation/Blender 4.1/blender.exeFull 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.
Tip

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:

  1. Reads the JSON action list from the path passed as the first positional argument after --.
  2. Iterates through actions in order.
  3. Dispatches each action's "type" key to the corresponding handler function.
  4. 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 stringRequired fieldsOptional fields
openblend_file
saveoutput_path
clean_scene
renderoutput_dirstart_frame, end_frame, file_format
set_render_engineengine
set_output_diroutput_dir
set_frame_rangestart_frame, end_frame
set_resolutionwidth, heightpercentage
export_fbxoutput_pathuse_selection, apply_modifiers
export_objoutput_pathuse_selection
export_gltfoutput_pathexport_format (GLB/GLTF_SEPARATE), use_selection
export_usdoutput_pathexport_textures
import_fbxfile_path
import_objfile_path
run_scriptscript_pathscript_args (dict)
apply_modifierobject_name, modifier_name
join_objectsobject_names (list)result_name
separate_objectsobject_namemode (LOOSE/MATERIAL)
set_materialobject_name, material_name
bakebake_type, output_pathobject_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_openblender_action_export_usdblender_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.

Warning

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.