ModelTranslator: 展开路径接入 UVPM4 排布——保底+增强,失败回退内置 pack
This commit is contained in:
@@ -103,6 +103,9 @@ def _decimate(obj, ratio):
|
|||||||
|
|
||||||
SEAM_ANGLE_DEG = 66.0 # 锐边阈值:两面夹角超此值标 seam
|
SEAM_ANGLE_DEG = 66.0 # 锐边阈值:两面夹角超此值标 seam
|
||||||
PACK_MARGIN = 0.002 # 岛间距 ≈ 2048 图 4px
|
PACK_MARGIN = 0.002 # 岛间距 ≈ 2048 图 4px
|
||||||
|
UVPM_EXT = "bl_ext.user_default.uvpackmaster4" # UVPackmaster 4 扩展模块名
|
||||||
|
UVPM_PIXEL_MARGIN = 4 # UVPM 岛间距(像素),与 PACK_MARGIN * UVPM_TEX_SIZE 同口径
|
||||||
|
UVPM_TEX_SIZE = 2048
|
||||||
|
|
||||||
|
|
||||||
def _clear_uv_layers(mesh):
|
def _clear_uv_layers(mesh):
|
||||||
@@ -204,21 +207,81 @@ def _overlap_fraction(obj):
|
|||||||
return round(sum(1 for p in polys if p.select) / float(len(polys)), 4)
|
return round(sum(1 for p in polys if p.select) / float(len(polys)), 4)
|
||||||
|
|
||||||
|
|
||||||
|
_uvpm_failed = False # 进程内失败一次即不再重试(避免重复警告与启动开销)
|
||||||
|
|
||||||
|
|
||||||
|
def _uvpm_enable():
|
||||||
|
"""启用 UVPM4 扩展(幂等)。headless 下先补丁 GPU shader 创建——
|
||||||
|
UVPM4 导入期为视口覆盖层建 shader,后台模式无 GPU 绘图会 SystemError;
|
||||||
|
覆盖层仅交互用,pack 不受影响。引擎路径经注册表自动发现。"""
|
||||||
|
import bpy
|
||||||
|
import addon_utils
|
||||||
|
if bpy.app.background:
|
||||||
|
import gpu
|
||||||
|
orig = gpu.shader.from_builtin
|
||||||
|
if not getattr(orig, "_mt_safe", False):
|
||||||
|
def _safe(*a, **k):
|
||||||
|
try:
|
||||||
|
return orig(*a, **k)
|
||||||
|
except SystemError:
|
||||||
|
return None
|
||||||
|
_safe._mt_safe = True
|
||||||
|
gpu.shader.from_builtin = _safe
|
||||||
|
# default_set=True 才建 preferences.addons 条目(UVPM4 register 依赖);
|
||||||
|
# factory-startup 关闭偏好自动保存,不会写盘
|
||||||
|
if addon_utils.enable(UVPM_EXT, default_set=True) is None:
|
||||||
|
raise RuntimeError("扩展 %s 启用失败(未安装或版本不兼容)" % UVPM_EXT)
|
||||||
|
|
||||||
|
|
||||||
|
def _uvpm_repack(obj, warnings):
|
||||||
|
"""UVPM4 重排当前 UV 布局,成功返回 True;任何失败记警告返回 False,
|
||||||
|
保底布局(pack_islands/smart_project)原样保留。"""
|
||||||
|
global _uvpm_failed
|
||||||
|
if _uvpm_failed:
|
||||||
|
return False
|
||||||
|
import bpy
|
||||||
|
try:
|
||||||
|
_uvpm_enable()
|
||||||
|
p = bpy.context.scene.uvpm4_props.default_main_props
|
||||||
|
p.pixel_margin_enable = True
|
||||||
|
p.pixel_margin = UVPM_PIXEL_MARGIN
|
||||||
|
p.pixel_margin_tex_size = UVPM_TEX_SIZE
|
||||||
|
bpy.context.scene.tool_settings.use_uv_select_sync = True
|
||||||
|
bpy.context.view_layer.objects.active = obj
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
|
try:
|
||||||
|
ret = bpy.ops.uvpackmaster4.pack(mode_id='pack.single_tile',
|
||||||
|
pack_op_type='0')
|
||||||
|
finally:
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
if 'FINISHED' not in ret:
|
||||||
|
raise RuntimeError("pack 返回 %s" % sorted(ret))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
_uvpm_failed = True
|
||||||
|
warnings.append("UVPackmaster 排布不可用(%s),沿用内置 pack 布局" % e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _do_unwrap(obj, mode, warnings):
|
def _do_unwrap(obj, mode, warnings):
|
||||||
"""按模式展开;seam 质量不达标自动回退 smart。返回 uv 指标 dict(含 mode)。"""
|
"""按模式展开(排布默认 UVPM4 增强,失败保底内置 pack);
|
||||||
|
seam 质量不达标自动回退 smart。返回 uv 指标 dict(含 mode)。"""
|
||||||
if mode == "seam":
|
if mode == "seam":
|
||||||
_unwrap_seam(obj, warnings)
|
_unwrap_seam(obj, warnings)
|
||||||
|
uvpm = _uvpm_repack(obj, warnings)
|
||||||
m = _collect_uv_metrics(obj)
|
m = _collect_uv_metrics(obj)
|
||||||
if uv_gate_ok(m["flipped"], m["overlap"]):
|
if uv_gate_ok(m["flipped"], m["overlap"]):
|
||||||
m["mode"] = "seam"
|
m["mode"] = uvpm_mode_label("seam", uvpm)
|
||||||
return m
|
return m
|
||||||
warnings.append("seam 展开质量不达标(翻转 %.1f%% 重叠 %s),回退 smart_project"
|
warnings.append("seam 展开质量不达标(翻转 %.1f%% 重叠 %s),回退 smart_project"
|
||||||
% (m["flipped"] * 100,
|
% (m["flipped"] * 100,
|
||||||
"%.1f%%" % (m["overlap"] * 100) if m["overlap"] is not None else "未知"))
|
"%.1f%%" % (m["overlap"] * 100) if m["overlap"] is not None else "未知"))
|
||||||
mode = "smart_fallback"
|
mode = "smart_fallback"
|
||||||
_unwrap_smart(obj)
|
_unwrap_smart(obj)
|
||||||
|
uvpm = _uvpm_repack(obj, warnings)
|
||||||
m = _collect_uv_metrics(obj)
|
m = _collect_uv_metrics(obj)
|
||||||
m["mode"] = mode if mode == "smart_fallback" else "smart"
|
m["mode"] = uvpm_mode_label(mode if mode == "smart_fallback" else "smart", uvpm)
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user