"""FBX 减面 CLI:减到指定三角面数并重展 UV(默认 RizomUV 自动展开),输出 <名>_low.fbx。 用法:python model_decimate.py src/well1500.fbx --tris 5000 [-o dir] [--unwrap rizom|seam|smart] [--rizom exe] [--blender exe]""" import argparse import os from mt_run import find_blender, run_blender_script def main(): ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("input", help="FBX 文件") ap.add_argument("--tris", type=int, required=True, help="目标三角面数") ap.add_argument("-o", "--out", default=None, help="输出目录(默认源文件同目录)") ap.add_argument("--unwrap", choices=("rizom", "seam", "smart"), default="rizom", help="UV 展开:rizom=RizomUV 自动切缝(默认,不可用回退 seam)," "seam=锐边接缝整岛展开,smart=Smart UV Project") ap.add_argument("--rizom", default=None, help="rizomuv.exe 路径(默认自动发现)") ap.add_argument("--blender", default=None) args = ap.parse_args() if args.tris <= 0: ap.error("--tris 必须为正整数") blender = find_blender(args.blender) name = os.path.splitext(os.path.basename(args.input))[0] outdir = args.out or os.path.dirname(os.path.abspath(args.input)) out_fbx = os.path.join(outdir, name + "_low.fbx") if args.unwrap == "rizom": # 三步:Blender 减面(不展UV)-> RizomUV 展开 -> Blender 质量门(不达标就地 seam 重展) s = run_blender_script(blender, "bl_decimate.py", [args.input, out_fbx, str(args.tris), "none"]) warnings = list(s["warnings"]) # 惰性导入:seam/smart 路径不依赖 rizom 模块 from rizom_unwrap import RizomError, find_rizomuv, rizom_unwrap try: rizom_unwrap(out_fbx, find_rizomuv(args.rizom)) except RizomError as e: warnings.append("RizomUV 不可用:%s" % e) except Exception as e: # 意外异常也不中断管线:记警告,交 bl_uvgate 回退 seam warnings.append("RizomUV 异常:%r" % e) g = run_blender_script(blender, "bl_uvgate.py", [out_fbx, "rizom"]) s["uv"] = g["uv"] s["warnings"] = warnings + g["warnings"] else: s = run_blender_script(blender, "bl_decimate.py", [args.input, out_fbx, str(args.tris), args.unwrap]) print("== %s: %d -> %d 面(目标 %d)-> %s" % (s["src"], s["tris_before"], s["tris_after"], s["target"], out_fbx)) u = s["uv"] overlap = "%.1f%%" % (u["overlap"] * 100) if u["overlap"] is not None else "n/a" print(" UV: 模式=%s 岛数=%d 利用率=%.1f%% 翻转=%.1f%% 重叠=%s" % (u["mode"], u["islands"], u["fill"] * 100, u["flipped"] * 100, overlap)) for w in s["warnings"]: print(" [警告] %s" % w) if __name__ == "__main__": main()