"""Drive Blender to photorealistically render the generated DrivAer car. Generates the part-labelled car mesh, dumps it to an npz, and runs Blender (Cycles, GPU) headless to produce a studio render of the REAL geometry - metallic paint, glass, chrome rims, rubber tyres, emissive lamps. This is the photoreal render of the actual 3D model (not a diffusion image), so it matches the car you can rotate / simulate / inspect. """ from __future__ import annotations import glob import os import subprocess import tempfile from pathlib import Path from typing import Optional import numpy as np HERE = Path(__file__).parent SCRIPT = HERE / "render_car_blender.py" _BLENDER = None def find_blender() -> Optional[str]: global _BLENDER if _BLENDER: return _BLENDER cands = [] import shutil p = shutil.which("blender") if p: cands.append(p) cands += sorted(glob.glob( r"C:\Program Files\Blender Foundation\Blender *\blender.exe"), reverse=True) cands += sorted(glob.glob( r"C:\Program Files\Blender Foundation\*\blender.exe"), reverse=True) for c in cands: if c and os.path.exists(c): _BLENDER = c return c return None def available() -> bool: return find_blender() is not None def _hex(color) -> str: import vehicle_realgen as G rgb = G.resolve_color(color) if isinstance(color, str) else color if rgb is None: rgb = (0.69, 0.71, 0.74) return "".join(f"{int(max(0,min(1,c))*255):02x}" for c in rgb[:3]) def render(length_mm=4700.0, width_mm=1900.0, height_mm=1450.0, roof=0.0, nose=0.0, rake=0.0, target_cd=None, color="silver", out_path: Optional[str] = None, timeout=600, mode="photoreal") -> Optional[str]: blender = find_blender() if blender is None: return None import drivaer_meshgen as MG d = MG.generate(length_mm=length_mm, width_mm=width_mm, height_mm=height_mm, roof=roof, nose=nose, rake=rake, target_cd=target_cd) if d is None: return None tmp = Path(tempfile.gettempdir()) / "chatcad_car_mesh.npz" np.savez(tmp, verts=d["verts"].astype(np.float32), faces=np.asarray(d["faces"], np.int32), region=np.asarray(d["region"], np.int32)) out_path = out_path or str(HERE / "output" / "blender_car.png") Path(out_path).parent.mkdir(parents=True, exist_ok=True) cmd = [blender, "-b", "-noaudio", "-P", str(SCRIPT), "--", str(tmp), out_path, _hex(color), mode] try: subprocess.run(cmd, timeout=timeout, capture_output=True) except Exception: return None return out_path if os.path.exists(out_path) else None if __name__ == "__main__": print("blender:", find_blender()) import time t = time.time() p = render(length_mm=4600, height_mm=1350, roof=0.6, nose=0.4, target_cd=0.24, color="red") print("rendered:", p, "in %.1fs" % (time.time() - t))