Files
HartOMat/render-worker/scripts/_blender_args.py
T
Hartmut c054236d22 fix: material override pipeline — pass --material-override CLI arg to Blender scripts
The initial implementation only overrode the material_map dict in the task,
but the Blender USD primvar path bypassed it. Now:
- Added --material-override named CLI arg parsed in _blender_args.py
- Both Mode A (factory) and Mode B (template) in _blender_scene_setup.py
  override usd_material_lookup and material_map when set
- Passed through full chain: task → step_processor → render_blender → CLI → Blender
- Tested: 175-part bearing rendered with single Steel-Bare material (1/1 materials)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:19:21 +01:00

118 lines
4.5 KiB
Python

"""Argument parsing for blender_render.py.
Parses positional and named CLI arguments passed after the '--' separator
when Blender is invoked as:
blender --background --python blender_render.py -- <glb_path> ...
"""
import json as _json
import os
import sys
from types import SimpleNamespace
def parse_args() -> SimpleNamespace:
"""Parse CLI arguments and return a SimpleNamespace of all render options."""
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
if len(argv) < 4:
print("Usage: blender --background --python blender_render.py -- "
"<glb_path> <output_path> <width> <height> ...")
sys.exit(1)
def _arg(n, default="", transform=str):
return transform(argv[n]) if len(argv) > n and argv[n] else default
glb_path = argv[0]
output_path = argv[1]
width = int(argv[2])
height = int(argv[3])
engine = _arg(4, "cycles", str.lower)
samples = _arg(5, None, int)
smooth_angle = _arg(6, 30, int)
cycles_device = _arg(7, "auto", str.lower)
transparent_bg = argv[8] == "1" if len(argv) > 8 else False
template_path = _arg(9, "")
target_collection = _arg(10, "Product")
material_library_path = _arg(11, "")
material_map = _json.loads(_arg(12, "{}")) if _arg(12, "{}") else {}
part_names_ordered = _json.loads(_arg(13, "[]")) if _arg(13, "[]") else []
lighting_only = argv[14] == "1" if len(argv) > 14 else False
shadow_catcher = argv[15] == "1" if len(argv) > 15 else False
rotation_x = _arg(16, 0.0, float)
rotation_y = _arg(17, 0.0, float)
rotation_z = _arg(18, 0.0, float)
noise_threshold = _arg(19, "")
denoiser = _arg(20, "")
denoising_input_passes = _arg(21, "")
denoising_prefilter = _arg(22, "")
denoising_quality = _arg(23, "")
denoising_use_gpu = _arg(24, "")
if samples is None:
samples = 64 if engine == "eevee" else 256
mesh_attributes: dict = {}
if "--mesh-attributes" in sys.argv:
_idx = sys.argv.index("--mesh-attributes")
try:
mesh_attributes = _json.loads(sys.argv[_idx + 1])
except Exception:
pass
usd_path = ""
if "--usd-path" in sys.argv:
_usd_idx = sys.argv.index("--usd-path")
usd_path = sys.argv[_usd_idx + 1] if _usd_idx + 1 < len(sys.argv) else ""
focal_length_mm = None
if "--focal-length" in sys.argv:
_fl_idx = sys.argv.index("--focal-length")
focal_length_mm = float(sys.argv[_fl_idx + 1]) if _fl_idx + 1 < len(sys.argv) else None
sensor_width_mm_override = None
if "--sensor-width" in sys.argv:
_sw_idx = sys.argv.index("--sensor-width")
sensor_width_mm_override = float(sys.argv[_sw_idx + 1]) if _sw_idx + 1 < len(sys.argv) else None
material_override = None
if "--material-override" in sys.argv:
_mo_idx = sys.argv.index("--material-override")
material_override = sys.argv[_mo_idx + 1] if _mo_idx + 1 < len(sys.argv) else None
if template_path and not os.path.isfile(template_path):
print(f"[blender_render] ERROR: template not found: {template_path}")
sys.exit(1)
return SimpleNamespace(
glb_path=glb_path,
output_path=output_path,
width=width,
height=height,
engine=engine,
samples=samples,
smooth_angle=smooth_angle,
cycles_device=cycles_device,
transparent_bg=transparent_bg,
template_path=template_path,
target_collection=target_collection,
material_library_path=material_library_path,
material_map=material_map,
part_names_ordered=part_names_ordered,
lighting_only=lighting_only,
shadow_catcher=shadow_catcher,
rotation_x=rotation_x,
rotation_y=rotation_y,
rotation_z=rotation_z,
noise_threshold=noise_threshold,
denoiser=denoiser,
denoising_input_passes=denoising_input_passes,
denoising_prefilter=denoising_prefilter,
denoising_quality=denoising_quality,
denoising_use_gpu=denoising_use_gpu,
mesh_attributes=mesh_attributes,
usd_path=usd_path,
use_template=bool(template_path),
focal_length_mm=focal_length_mm,
sensor_width_mm=sensor_width_mm_override,
material_override=material_override,
)