ModelTranslator: rizom_unwrap exe 发现(CLI>env>注册表>默认,官方 README 口径)
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
"""RizomUV 自动展开:官方 RizomUVLink 驱动 rizomuv.exe 做 AutoSeam/Unfold/Pack。
|
||||||
|
仅在系统 Python 中使用(不进 Blender);任何不可用/失败抛 RizomError,
|
||||||
|
由 model_decimate.py 回退 Blender seam 展开。"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
|
||||||
|
DEFAULT_RIZOM = r"C:\Program Files\RizomUV2025\rizomuv.exe"
|
||||||
|
MAP_RES = 2048 # Pack 目标贴图分辨率
|
||||||
|
PADDING_PX = 4 # 岛间距(像素)= bl_decimate.PACK_MARGIN(0.002) * 2048
|
||||||
|
TIMEOUT_S = 300 # 单条命令超时
|
||||||
|
|
||||||
|
|
||||||
|
class RizomError(Exception):
|
||||||
|
"""RizomUV 不可用或处理失败(上层据此回退)。"""
|
||||||
|
|
||||||
|
|
||||||
|
def candidate_paths(cli_arg=None, env_val=None, reg_val=None, default=DEFAULT_RIZOM):
|
||||||
|
"""rizomuv.exe 候选路径,优先级:CLI 参数 > 环境变量 > 注册表 > 默认安装位置。"""
|
||||||
|
return [p for p in (cli_arg, env_val, reg_val, default) if p]
|
||||||
|
|
||||||
|
|
||||||
|
def registry_rizom_path():
|
||||||
|
"""官方 README 的注册表查找(HKLM\\SOFTWARE\\Rizom Lab\\RizomUV VS RS 202X.Y),
|
||||||
|
新版本优先;找不到或非 Windows 返回 None。"""
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
except ImportError:
|
||||||
|
return None
|
||||||
|
for i in range(9, 1, -1):
|
||||||
|
for j in range(10, -1, -1):
|
||||||
|
if i == 2 and j < 2:
|
||||||
|
continue
|
||||||
|
key_path = "SOFTWARE\\Rizom Lab\\RizomUV VS RS 202%d.%d" % (i, j)
|
||||||
|
try:
|
||||||
|
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path)
|
||||||
|
return winreg.QueryValue(key, "rizomuv.exe")
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_rizomuv(cli_arg=None, use_registry=True, default=DEFAULT_RIZOM):
|
||||||
|
"""返回第一个真实存在的 rizomuv.exe;都不存在抛 RizomError。"""
|
||||||
|
reg = registry_rizom_path() if use_registry else None
|
||||||
|
cands = candidate_paths(cli_arg, os.environ.get("RIZOMUV_EXE"), reg, default)
|
||||||
|
for p in cands:
|
||||||
|
if os.path.isfile(p):
|
||||||
|
return p
|
||||||
|
raise RizomError("找不到 rizomuv.exe(尝试过:%s)" % "; ".join(cands))
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
import rizom_unwrap as ru
|
||||||
|
|
||||||
|
|
||||||
|
class TestCandidatePaths(unittest.TestCase):
|
||||||
|
def test_priority_order(self):
|
||||||
|
self.assertEqual(ru.candidate_paths("a.exe", "b.exe", "c.exe"),
|
||||||
|
["a.exe", "b.exe", "c.exe", ru.DEFAULT_RIZOM])
|
||||||
|
|
||||||
|
def test_none_entries_skipped(self):
|
||||||
|
self.assertEqual(ru.candidate_paths(None, None, None), [ru.DEFAULT_RIZOM])
|
||||||
|
|
||||||
|
def test_env_only(self):
|
||||||
|
self.assertEqual(ru.candidate_paths(None, "b.exe", None),
|
||||||
|
["b.exe", ru.DEFAULT_RIZOM])
|
||||||
|
|
||||||
|
|
||||||
|
class TestFindRizomuv(unittest.TestCase):
|
||||||
|
def test_missing_exe_raises(self):
|
||||||
|
os.environ.pop("RIZOMUV_EXE", None)
|
||||||
|
with self.assertRaises(ru.RizomError):
|
||||||
|
ru.find_rizomuv("Z:/no/such/rizomuv.exe", use_registry=False,
|
||||||
|
default="Z:/no/default.exe")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user