Files
esh-pfi-infrastructure/docs/fleettools/blender.md
T

77 lines
4.8 KiB
Markdown

# Blender: headless and agent-driven 3D on fv-ml1 GPU 3
**Blender 5.2.2 LTS** (bundled Python 3.13), runs on **fv-ml1 GPU 3** (RTX PRO 6000 Blackwell,
96 GB). Stack and full notes: `/home/lkraven/development/eshpfi-management/stacks/blender/README.md`.
⚠ **GPU 3 is borrowed.** It is the fleet's reserve card for a full-size vLLM seat. Blender
runs only while in use, and this access ends if a big seat moves onto the card.
## Two ways in
| You are… | Use | Shape |
|---|---|---|
| a script or CLI caller (renders, conversions) | `scripts/blender-run` | one-shot `docker run --rm`: no desktop, gone when Blender exits |
| an agent building scenes interactively | `scripts/blender-mcp` (MCP, per task) | a GUI Blender plus the mcp-for-blender add-on; `up` / `status` / `down` |
Both scripts are in `/home/lkraven/development/eshpfi-management/scripts/` and run from nh3-dev,
reaching fv-ml1 as `infra-ops@10.251.50.54` over ssh. **No HTTP API** and no openapi.json.
## blender-run (headless)
```sh
scripts/blender-run --job /path/to/jobdir -- --python render.py -- out.png
scripts/blender-run --extensions --job /path/to/jobdir -- --python model.py
scripts/blender-run -- --python-expr 'import bpy; print(bpy.app.version_string)'
```
- Always adds `-b --factory-startup --python-exit-code 1`. Arguments go after `--`.
- **Files:** fv-ml1 does not mount `/mnt/smithy`. `--job DIR` mirrors DIR to
`fv-ml1:/tank/blender/jobs/<basename>-<hash of DIR's absolute path>/`, runs with that as
the working directory, and copies new or changed files back into DIR. Nothing is ever
deleted locally, and a rerun starts from an exact mirror, never from leftovers. Use
relative input paths inside the job. Do not run the same DIR twice at once.
- **Engines headless (tested 2026-09-28):** Cycles on GPU (OptiX/CUDA), Cycles on CPU, EEVEE
(EGL, no display needed, ~9 s with the shader compile on first use), Workbench. In 5.2 the
EEVEE id is `BLENDER_EEVEE` (`BLENDER_EEVEE_NEXT` is gone). For Cycles GPU, set
`prefs.compute_device_type = 'OPTIX'` and enable the OPTIX devices, then
`scene.cycles.device = 'GPU'`. Factory startup defaults to CPU.
- **Import:** STL is built in (`bpy.ops.wm.stl_import`). STEP, 3MF and the other add-ons need
`--extensions` (below).
- **`--extensions`** enables the pinned add-on set: SurfacePsycho 0.10.4 (NURBS patches, STEP/IGES
export via its bundled OCP), CAD Sketcher 0.32.1, 3D-Print Toolbox 1.4.1, STEP Importer 1.2.1,
Bool Tool 2.1.0, LoopTools 4.7.7, MeasureIt 1.8.4, 3MF Import/Export 2.7.7. Pins:
`stacks/blender/extensions.lock`. If any add-on fails to enable, the run exits 1 before your
script starts. It adds a few seconds of startup (the add-on wheels unpack per run), so it is
off by default. **CAD Sketcher's sketch operators need the GUI** (they activate a workspace
tool); headless they fail with "'NoneType' object has no attribute 'widget'". Operators that
want a 3D View (MeasureIt, LoopTools) take a `bpy.context.temp_override(area=...)` with a
screen datablock's VIEW_3D area. Worked calls for every add-on:
`scripts/blender-probes/extensions_acceptance.py`. Full notes and foot-guns: the stack README,
section "Extensions".
- **`--cpu`** attaches no GPU at all (no nvidia runtime), so the run never touches GPU 3. Use it
for modelling, add-ons and import/export, which is anything that does not render. It is proven
for those (the extension acceptance ran that way) and for Cycles on CPU. EEVEE and Workbench
are expected to fail without the GPU (untested). The container hostname is always
`fv-ml1-blender`.
- **Budget:** each run is capped at 64 GB RAM and 48 CPUs, with up to the whole 96 GB of VRAM.
Keep to about 2 concurrent renders. It is not on irv-ml1, so irv-ml1's working-set budget
does not apply.
⚠ **Foot-guns** (all measured):
- A `--python` script that raises exits **0** unless `--python-exit-code` is set. blender-run
sets it.
- `render.filepath` must be **absolute**. Blender does not resolve a relative output path
against the working directory ("cannot save 'out.png'"). Importers and Python file I/O do.
- Harmless stderr noise: "HIPEW initialization failed" (the AMD backend probing), and "Failed to
create secure directory (/defaults): Operation not permitted" (the image's runtime-dir setup
running as a non-root user; reported by draupnir 2026-09-28).
- The first OptiX render in a process includes about 1-2 s of kernel load.
## blender-mcp (agents)
Register it **per task**, never user- or project-wide (Prime, 2026-09-27):
`claude mcp add blender -- /home/lkraven/development/eshpfi-management/scripts/blender-mcp`.
Then run `scripts/blender-mcp up`, wait for `status` to say answering, work, and run `down`
when finished. Safe mode is on (no os/open/network in agent code), so the startup hook has
already pointed Cycles at OptiX. Save to `/work/…`. Details and traps are in the stack README.