Spaces:
Running
Running
| """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)) | |