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:
@@ -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] = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user