Files
AIC-Project/Tools/ModelTranslator/qr_bridge.py
T

82 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""QR 桥纯逻辑:引擎发现、面数换算、settings 生成、progress 解析。不 import bpy。
减面可选后端 Quad Remesher 用——headless 直接调 Engine/xremesh.exe,绕开 modal 操作符。"""
import glob
import os
QR_TIMEOUT = 120.0 # 引擎轮询超时(秒)
QR_INPUT_CAP = 50000 # quad 后端 QR 前预 collapse 的中等密度目标面数
QR_HOLE_MAX_SIDES = 6 # 补洞上限边数:只补 <=6 边的薄部位小洞
QR_CATASTROPHIC_TOL = 12 # 软水密门容忍:补洞后仍多出超此数的开边/非流形才判灾难性
def find_qr_engine():
"""定位 QuadRemesher 的 xremesh.exe;找不到返回 None。
顺序:QR_ENGINE 环境变量(权威:显式设了就以它为准,无效即 None,不再自动发现)
-> 标准 addon 路径(取字典序最大目录,当前 Blender 5.x 下即最高版本)。"""
env = os.environ.get("QR_ENGINE")
if env:
return env if os.path.isfile(env) else None
appdata = os.environ.get("APPDATA")
if not appdata:
return None
pattern = os.path.join(
appdata, "Blender Foundation", "Blender", "*",
"scripts", "addons", "QuadRemesher", "Engine", "xremesh.exe")
hits = sorted(glob.glob(pattern))
return hits[-1] if hits else None
def tris_to_target_quads(tris):
"""三角面数换算 QR 目标四边形数:1 quad ≈ 2 tris,至少 1。"""
return max(1, int(tris) // 2)
def build_settings(in_fbx, out_fbx, prog, target_quads,
adaptive=50, exact=False, hard_edges=True):
"""生成 RetopoSettings.txt 文本(xremesh.exe -s 读取)。"""
lines = [
"HostApp=Blender",
'FileIn="%s"' % in_fbx,
'FileOut="%s"' % out_fbx,
'ProgressFile="%s"' % prog,
"TargetQuadCount=%d" % target_quads,
"CurvatureAdaptivness=%d" % adaptive,
"ExactQuadCount=%d" % (1 if exact else 0),
"UseVertexColorMap=False",
"UseMaterialIds=0",
"UseIndexedNormals=0",
"AutoDetectHardEdges=%d" % (1 if hard_edges else 0),
]
return "\n".join(lines) + "\n"
def parse_progress(text):
"""解析 progress.txt -> (state, msg)。
首行 '2'=success<0=error(次行为文本);空/分数/非法=running。"""
lines = text.splitlines()
if not lines:
return ("running", "")
try:
v = float(lines[0])
except ValueError:
return ("running", "")
if v == 2:
return ("success", "")
if v < 0:
return ("error", lines[1] if len(lines) > 1 else "")
return ("running", "")
def topology_acceptable(src_boundary, src_nonmanifold,
out_boundary, out_nonmanifold, tol=0):
"""QR 输出拓扑是否可接受:不比输入多出超过 tol 的开边(孔洞)/非流形边。
tol=0(默认)为零容忍严格门;quad 后端补小洞后用 tol=QR_CATASTROPHIC_TOL 只挡灾难性破损。"""
return (out_boundary <= src_boundary + tol
and out_nonmanifold <= src_nonmanifold + tol)
def precollapse_target(face_count, cap=QR_INPUT_CAP):
"""QR 前预 collapse 目标:面数 > cap 返回 cap(先减到中等密度),否则 None(跳过)。
高密度网格直接 QR 必破洞,先 collapse 到中等密度给 QR 一个稳定输入。"""
return cap if face_count > cap else None