46 lines
2.1 KiB
Python
46 lines
2.1 KiB
Python
"""find_blender / run_blender_script:model_decimate 与 model_bake 共享的
|
||
headless Blender 运行器(与 model_translator.py 同模式,脚本名与参数泛化)。"""
|
||
import collections
|
||
import json
|
||
import os
|
||
import shutil
|
||
import subprocess
|
||
import sys
|
||
|
||
DEFAULT_BLENDER = r"D:\tools\blender-5.0.0-windows-x64\blender.exe"
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
|
||
|
||
def find_blender(cli_arg):
|
||
for cand in (cli_arg, os.environ.get("BLENDER_EXE"), DEFAULT_BLENDER,
|
||
shutil.which("blender")):
|
||
if cand and os.path.isfile(cand):
|
||
return cand
|
||
sys.exit("找不到 blender.exe,请用 --blender 指定或设置环境变量 BLENDER_EXE")
|
||
|
||
|
||
def run_blender_script(blender, script, script_args, blender_args=()):
|
||
"""跑 HERE 下的 bl_*.py,返回 MT_SUMMARY JSON;失败或 summary 带 error 则退出。
|
||
流式读子进程输出:`MT_PROGRESS ` 行实时转发到本进程 stdout(供上层 UI 显示阶段进度),
|
||
`MT_SUMMARY ` 行解析为结果,其余行仅缓存尾部用于出错诊断。stderr 并入 stdout 防管道死锁。"""
|
||
cmd = [blender, "-b", *blender_args, "--factory-startup",
|
||
"--python", os.path.join(HERE, script), "--"] + list(script_args)
|
||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||
text=True, encoding="utf-8", errors="replace", bufsize=1)
|
||
summary = None
|
||
tail = collections.deque(maxlen=400)
|
||
for line in proc.stdout:
|
||
line = line.rstrip("\r\n")
|
||
if line.startswith("MT_SUMMARY "):
|
||
summary = json.loads(line[len("MT_SUMMARY "):])
|
||
elif line.startswith("MT_PROGRESS "):
|
||
print(line[len("MT_PROGRESS "):], flush=True) # 实时透传给上层
|
||
else:
|
||
tail.append(line)
|
||
proc.wait()
|
||
if proc.returncode != 0 or summary is None or "error" in summary:
|
||
sys.stderr.write("\n".join(tail)[-2000:] + "\n")
|
||
err = summary["error"] if summary and "error" in summary else script
|
||
sys.exit("Blender 执行失败:%s" % err)
|
||
return summary
|