torch and the compiled texture_baker/uv_unwrapper each link a libomp. Allowing the duplicate runtime clears 'OMP: Error #15' but the duplicate then corrupts the multithreaded CPU LAPACK path (torch.linalg.svd MPS fallback) -> segfault with no Python traceback. Forcing OMP_NUM_THREADS=1 + MKL_NUM_THREADS=1 removes the threading collision. Verified: clean 1.3MB GLB (13298 verts) in ~5s on M3 Ultra, 9GB peak. SF3D local image->3D now works (weights unlocked by owner HF license). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[3]
|
|
VENDOR = ROOT / "vendor" / "stable-fast-3d"
|
|
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--input", action="append", default=[])
|
|
ap.add_argument("--outdir", required=True)
|
|
ap.add_argument("--params", default="{}")
|
|
a = ap.parse_args()
|
|
p = json.loads(a.params)
|
|
|
|
if not a.input:
|
|
print("ERROR: no input image")
|
|
sys.exit(1)
|
|
if not (VENDOR / "run.py").exists():
|
|
print(f"ERROR: SF3D not installed at {VENDOR}. Run scripts/install_sf3d.sh")
|
|
sys.exit(1)
|
|
|
|
outdir = Path(a.outdir)
|
|
work = outdir / "sf3d_out"
|
|
work.mkdir(parents=True, exist_ok=True)
|
|
|
|
cmd = [
|
|
sys.executable, "run.py", str(Path(a.input[0]).resolve()),
|
|
"--device", p.get("device", "mps"),
|
|
"--output-dir", str(work.resolve()),
|
|
"--texture-resolution", str(p.get("texture_resolution", 1024)),
|
|
"--foreground-ratio", str(p.get("foreground_ratio", 0.85)),
|
|
"--remesh_option", p.get("remesh_option", "none"),
|
|
]
|
|
env = os.environ.copy()
|
|
env["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
|
|
# torch and the compiled texture_baker/uv_unwrapper each link a libomp. Allowing
|
|
# the duplicate runtime avoids "OMP: Error #15", but the duplicate then corrupts
|
|
# the multithreaded CPU LAPACK call (torch.linalg.svd MPS fallback) and segfaults
|
|
# — forcing single-threaded OpenMP removes the threading collision. Verified: a
|
|
# clean GLB on M3 Ultra with all three set.
|
|
env["KMP_DUPLICATE_LIB_OK"] = "TRUE"
|
|
env["OMP_NUM_THREADS"] = "1"
|
|
env["MKL_NUM_THREADS"] = "1"
|
|
print("+", " ".join(cmd), flush=True)
|
|
res = subprocess.run(cmd, cwd=str(VENDOR), env=env, stdout=sys.stdout, stderr=subprocess.STDOUT)
|
|
if res.returncode != 0:
|
|
sys.exit(res.returncode)
|
|
|
|
glbs = sorted(work.rglob("*.glb"))
|
|
if not glbs:
|
|
print("ERROR: SF3D produced no .glb")
|
|
sys.exit(1)
|
|
name = f"sf3d_{Path(a.input[0]).stem}.glb"
|
|
(outdir / "result.json").write_text(json.dumps(
|
|
{"outputs": [{"path": str(glbs[0]), "name": name, "meta": {"tool": "sf3d"}}]}))
|
|
print("done:", glbs[0], flush=True)
|