refactor(P1): M1 dead code removal + M3 blender_render.py split

M1 — dead code removed:
- Delete blender-renderer/ and threejs-renderer/ source files
- Remove PIL/Pillow fallback block from step_processor.py
  (_generate_thumbnail_placeholder, _finalise_image JPG path)
- Remove stl_quality param from render_blender.py, render_still_task,
  render_turntable_task (was always "low"; hardcode deflection values)
- render_turntable_task now reads scene_linear/angular_deflection from
  system_settings (consistent with export_glb.py pipeline)

M3 — blender_render.py split from 263 → 68 lines:
- _blender_args.py: parse_args() — all 25 positional + named args
- _blender_scene_setup.py: setup_scene() — MODE A/B including USD import
- _blender_render_config.py: configure_and_render() — engine + output

Post-review fixes:
- _db_engine.dispose() after settings read in render_turntable_task
- _finalise_image() fmt param removed (always PNG; PIL never installed)
- _blender_import.py committed together with new submodules to satisfy
  import_usd_file dependency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 12:54:40 +01:00
parent 393e4b92a7
commit 47b5d42bb5
10 changed files with 471 additions and 496 deletions
+41 -22
View File
@@ -15,17 +15,13 @@ from pathlib import Path
logger = logging.getLogger(__name__)
def _glb_from_step(step_path: Path, glb_path: Path, quality: str = "low") -> None:
"""Convert STEP → GLB via OCC (export_step_to_gltf.py, no Blender needed).
quality: "low" → coarser mesh (~0.3 mm deflection, fast)
"high" → finer mesh (~0.05 mm deflection, slower)
"""
def _glb_from_step(step_path: Path, glb_path: Path) -> None:
"""Convert STEP → GLB via OCC (export_step_to_gltf.py, no Blender needed)."""
import subprocess
import sys as _sys
linear_deflection = 0.3 if quality == "low" else 0.05
angular_deflection = 0.5 if quality == "low" else 0.2
linear_deflection = 0.3
angular_deflection = 0.5
scripts_dir = Path(os.environ.get("RENDER_SCRIPTS_DIR", "/render-scripts"))
script_path = scripts_dir / "export_step_to_gltf.py"
@@ -71,7 +67,6 @@ def render_still(
height: int = 512,
engine: str = "cycles",
samples: int = 256,
stl_quality: str = "low",
smooth_angle: int = 30,
cycles_device: str = "auto",
transparent_bg: bool = False,
@@ -94,9 +89,13 @@ def render_still(
denoising_use_gpu: str = "",
mesh_attributes: dict | None = None,
log_callback: "Callable[[str], None] | None" = None,
usd_path: "Path | None" = None,
) -> dict:
"""Convert STEP → GLB (OCC) → PNG (Blender subprocess).
When usd_path is provided and the file exists, the GLB conversion step is
skipped and Blender imports the USD stage directly (--usd-path flag).
Returns a dict with timing, sizes, engine_used, and log_lines.
Raises RuntimeError on failure.
"""
@@ -116,15 +115,20 @@ def render_still(
t0 = time.monotonic()
# 1. GLB conversion (OCC — replaces cadquery STL)
# 1. GLB conversion (OCC)skipped when usd_path is provided
glb_path = step_path.parent / f"{step_path.stem}_thumbnail.glb"
use_usd = bool(usd_path and usd_path.exists())
t_glb = time.monotonic()
if not glb_path.exists() or glb_path.stat().st_size == 0:
_glb_from_step(step_path, glb_path, quality=stl_quality)
if use_usd:
logger.info("[render_blender] using USD path: %s", usd_path)
glb_size_bytes = 0
else:
logger.info("GLB local hit: %s (%d KB)", glb_path.name, glb_path.stat().st_size // 1024)
glb_size_bytes = glb_path.stat().st_size if glb_path.exists() else 0
if not glb_path.exists() or glb_path.stat().st_size == 0:
_glb_from_step(step_path, glb_path)
else:
logger.info("GLB local hit: %s (%d KB)", glb_path.name, glb_path.stat().st_size // 1024)
glb_size_bytes = glb_path.stat().st_size if glb_path.exists() else 0
glb_duration_s = round(time.monotonic() - t_glb, 2)
# 2. Blender render
@@ -142,12 +146,14 @@ def render_still(
env["EGL_PLATFORM"] = "surfaceless"
def _build_cmd(eng: str) -> list:
# Pass "" as glb_path when using USD — blender_render.py reads --usd-path instead
glb_arg = "" if use_usd else str(glb_path)
cmd = [
blender_bin,
"--background",
"--python", str(script_path),
"--",
str(glb_path),
glb_arg,
str(output_path),
str(width), str(height),
eng, str(samples), str(smooth_angle),
@@ -165,7 +171,11 @@ def render_still(
denoising_input_passes or "", denoising_prefilter or "",
denoising_quality or "", denoising_use_gpu or "",
]
if mesh_attributes:
if use_usd:
cmd += ["--usd-path", str(usd_path)]
if mesh_attributes:
logger.debug("[render_blender] usd_path active — mesh_attributes ignored")
elif mesh_attributes:
cmd += ["--mesh-attributes", json.dumps(mesh_attributes)]
return cmd
@@ -283,7 +293,6 @@ def render_turntable_to_file(
height: int = 1920,
engine: str = "cycles",
samples: int = 128,
stl_quality: str = "low",
smooth_angle: int = 30,
cycles_device: str = "auto",
transparent_bg: bool = False,
@@ -300,9 +309,12 @@ def render_turntable_to_file(
rotation_x: float = 0.0,
rotation_y: float = 0.0,
rotation_z: float = 0.0,
usd_path: "Path | None" = None,
) -> dict:
"""Render a turntable animation: STEP → STL → N frames (Blender) → mp4 (ffmpeg).
When usd_path is provided and exists, the GLB conversion step is skipped.
Returns a dict with timing, frame count, engine_used, log_lines.
Raises RuntimeError on failure.
"""
@@ -328,14 +340,18 @@ def render_turntable_to_file(
t0 = time.monotonic()
# 1. GLB conversion (OCC — replaces cadquery STL)
# 1. GLB conversion (OCC)skipped when usd_path is provided
glb_path = step_path.parent / f"{step_path.stem}_thumbnail.glb"
use_usd = bool(usd_path and usd_path.exists())
t_glb = time.monotonic()
if not glb_path.exists() or glb_path.stat().st_size == 0:
_glb_from_step(step_path, glb_path, quality=stl_quality)
if use_usd:
logger.info("[render_blender] turntable using USD path: %s", usd_path)
else:
logger.info("GLB local hit: %s (%d KB)", glb_path.name, glb_path.stat().st_size // 1024)
if not glb_path.exists() or glb_path.stat().st_size == 0:
_glb_from_step(step_path, glb_path)
else:
logger.info("GLB local hit: %s (%d KB)", glb_path.name, glb_path.stat().st_size // 1024)
glb_duration_s = round(time.monotonic() - t_glb, 2)
# 2. Render frames with Blender
@@ -346,12 +362,13 @@ def render_turntable_to_file(
env = dict(os.environ)
env["EGL_PLATFORM"] = "surfaceless"
glb_arg = "" if use_usd else str(glb_path)
cmd = [
blender_bin,
"--background",
"--python", str(script_path),
"--",
str(glb_path),
glb_arg,
str(frames_dir),
str(frame_count),
"360", # degrees
@@ -371,6 +388,8 @@ def render_turntable_to_file(
bg_color or "",
"1" if transparent_bg else "0",
]
if use_usd:
cmd += ["--usd-path", str(usd_path)]
log_lines: list[str] = []