ModelTranslator: 按 spike 结论改 UV 观察图为 PIL 两端架构

headless Blender export_layout(PNG) 走 GPUOffScreen 不可用;改为
Blender 抽 UV 几何→sidecar JSON→系统 Python(Pillow) 绘 PNG。
拆 Task 5(绘图 TDD)/6(抽几何)/7(渲染清理),README 加 Pillow 依赖。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
ud18010
2026-07-21 11:11:26 +08:00
co-authored by Claude Opus 4.8
parent 890d12fb09
commit f0046ea64d
2 changed files with 215 additions and 84 deletions
@@ -25,7 +25,7 @@
- 不抽独立「多候选择优」模块;改动内联进现有函数。
- 观察图仅纯 UV 线框,不叠贴图/棋盘格(减面阶段尚无烘焙贴图)。
- 不改 `model_bake.py` / `model_translator.py` / UVPM 排布逻辑。
- 不引入 matplotlib/PIL 等新依赖。
- ~~不引入 matplotlib/PIL 等新依赖。~~ **2026-07-21 修订)** headless Blender 的 `export_layout(mode='PNG')` 走 GPUOffScreen,后台模式不可用(`SystemError: GPU functions ... not available in background mode`);`mode='SVG'` 可用但非位图。经用户确认,观察图改为**用系统 Python 的 Pillow 自绘 PNG 线框**——引入 Pillow 依赖(系统 Python 已装 12.2.0Blender 自带 Python 无 PIL)。
## 设计
@@ -64,17 +64,16 @@ bpy.ops.uv.pack_islands(rotate=True, margin=PACK_MARGIN) # 已有
**质量门与常量**`UV_FLIP_TOL`/`UV_OVERLAP_TOL`/`uv_gate_ok` 不变。新增 `SEAM_ANGLE_SWEEP`
### 3. UV 线框观察图导出
### 3. UV 线框观察图Blender 抽几何 → 系统 Python 用 PIL 绘 PNG
最终 UV 定下后(UVPM 重排完成后),导出线框 PNG
因 headless 无法用 Blender 直接出 PNG(见非目标修订),拆成两端
- 算子:`bpy.ops.uv.export_layout(filepath=..., mode='PNG', size=(UV_PREVIEW_SIZE, UV_PREVIEW_SIZE), opacity=UV_PREVIEW_OPACITY)`
- 新增常量 `UV_PREVIEW_SIZE = 1024``UV_PREVIEW_OPACITY = 0.25`
- 需要正确上下文:对象激活、edit mode、UV 全选。实现时验证 headless 可行性。
- 输出路径:紧邻 `_low.fbx`,命名 `<名>_low_uv.png`(由 `out_fbx` 派生:同目录、`os.path.splitext(out_fbx)[0] + "_uv.png"`
- 失败:`try/except``RuntimeError`/`SystemError`)记警告、不中断FBX 照常产出。
- 封装为 `_export_uv_layout(obj, uv_png_path, warnings)` `main()` 导出 FBX 前后择一时机调用(需在切回 OBJECT 模式前后处理好上下文)
- `MT_SUMMARY` JSON 增加字段 `uv_preview`(路径或 null)。
**Blender 端(`bl_decimate.py`**:最终 UV 定下后,`_collect_uv_polygons(obj)` 用 bmesh 提取每个面的 UV 多边形(归一化 0-1 坐标)`[[[u,v],...], ...]``main()` 写入 sidecar JSON `<名>_low_uv.polys.json``MT_SUMMARY` 增加字段 `uv_preview`(目标 PNG 路径 `<名>_low_uv.png`)与 `uv_polys`sidecar JSON 路径);抽取失败记警告、两字段置 null、不中断
**系统 Python 端(`uv_preview.py` + `model_decimate.py`**
- 新模块 `uv_preview.py` 提供纯函数 `render_uv_png(polygons, out_png, size=1024, pad=8, ...)`:白底、半透明填充 + 深色线框(V 轴翻转到图像坐标),用 Pillow 绘制并存 PNG。可在系统 Python 单测
- `model_decimate.py` 拿到 summary 后:读 `uv_polys` JSON → 调 `render_uv_png` 输出到 `uv_preview` → 删除 sidecar JSON → 打印 PNG 路径;任一步失败打印警告、不中断FBX 产出
- 输出:紧邻 `_low.fbx`命名 `<名>_low_uv.png`
### 4. CLI 输出(model_decimate.py