Files
AIC-Project/docs/superpowers/specs/2026-07-21-uvpm-packing-utilization-design.md
T

114 lines
6.6 KiB
Markdown
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.
# UVPM 排布利用率优化:开启旋转 + 启发式搜索
日期:2026-07-21
范围:`Tools/ModelTranslator/bl_decimate.py``_uvpm_repack`)、`README.md`
## 背景与动机
减岛优化后 gargoyle 3000 面走 seam@45、390 岛,但 UV 利用率仅 **52.3%**——约 48% 为空白(烘焙时填黑,用户观感为"错误的黑色块")。
根因定位(已查 `_uvpm_repack` `bl_decimate.py:286-314`):
- 当前 UVPM 调用只设 `pixel_margin`4px@2048),**旋转/启发式搜索全用 UVPM4 默认值**:`bpy.ops.uvpackmaster4.pack(mode_id='pack.single_tile', pack_op_type='0')`
- gargoyle 减面后 UV 由大量**又长又斜的薄条岛**(尖刺/薄翅缘几何)主导。薄斜条在缺乏精细旋转对齐时外接矩形浪费极大——这是 packer 效率的天敌。
- UVPM 的旋转 + 启发式迭代搜索正是为此类不规则岛设计的,当前未启用。
用户选择:**只调 UVPM 排布**(不碰边距/烘焙),启发式耗时可接受(离线工具,设时间上限)。
## 目标
开启 UVPM4 的旋转与启发式搜索,把薄条岛塞得更紧,**明显提升 gargoyle 3000 的 UV 利用率**,且不退化其他指标(岛数、翻转、重叠不变差)。
## 非目标(YAGNI
- 不改像素边距 `pixel_margin`4px)与 `model_bake` 的烘焙 padding(避免渗色,用户明确排除)。
- 不改展开/减岛/清理逻辑(`_do_unwrap``_clean_mesh``--max-overlap` 均不动)。
- 不动 `average_islands_scale`(纹素均匀,保留)。
- 不追求硬性利用率数字(薄条几何天然受限),只求"明显上升"。
## 设计
### 1. UVPM4 属性探针(实现首步 spike)
因 UVPM4 属性名/默认值随版本可能不同,先用一次性脚本确认,避免猜 API:
- 启用 UVPM4(复用 `_uvpm_enable` 的 headless GPU 补丁思路)。
- 枚举 `bpy.context.scene.uvpm4_props.default_main_props` 中旋转/启发式相关属性:名字、默认值、类型/取值范围(候选:`rotation_enable``rotation_step``rotation_step_value``heuristic_enable``heuristic_search_time``heuristic_max_wait_time` 等)。
- 在测试网格(UV 球 + smart_project)上开启这些属性跑一次 `uvpackmaster4.pack`,确认 headless 不报错、返回 `FINISHED`
- 产出:确切属性名与合理取值,供第 2 节定稿;脚本用完删除、不入库。
### 2. `_uvpm_repack` 开启旋转 + 启发式
新增防御式辅助与常量,在 `_uvpm_repack``bl_decimate.py:294-305`)的 `pixel_margin` 设置之后、`pack` 调用之前设置属性:
```python
# 常量(值以探针结论为准,示意)
UVPM_ROTATION_STEP = <探针定> # 旋转步进(度),更细利于薄条对齐
UVPM_HEURISTIC_TIME = <探针定> # 启发式搜索秒数上限(如 510
def _uvpm_set(p, name, value, warnings):
"""防御式设 UVPM 属性:属性存在才设,否则记警告跳过——
名字不匹配(版本差异)时降级为按原 margin 跑 UVPM,不丢整个排布。"""
if hasattr(p, name):
setattr(p, name, value)
else:
warnings.append("UVPM 属性 %s 不存在,跳过" % name)
```
`_uvpm_repack` 内(属性名以探针为准):
```python
_uvpm_set(p, "rotation_enable", True, warnings)
_uvpm_set(p, "rotation_step", UVPM_ROTATION_STEP, warnings)
_uvpm_set(p, "heuristic_enable", True, warnings)
_uvpm_set(p, "heuristic_search_time", UVPM_HEURISTIC_TIME, warnings)
```
- 属性设置在现有 `try/except Exception``bl_decimate.py:293-314`)内——但用 `_uvpm_set``hasattr` 守卫,使**单个属性名不匹配只跳过该项、不抛异常**,从而不会触发整体失败回退(那会丢掉 UVPM 全部排布)。
- 旋转后的 UV 对烘焙无影响(烘焙按 UV 原样采样)。
- 边距、`pack` 调用签名(`mode_id`/`pack_op_type`)保持不变,除非探针发现启发式必须换 `pack_op_type`(若如此,在第 2 节据实调整并记录)。
### 3. 数据流(不变,仅 UVPM 内部行为增强)
```
… → _do_unwrap → 选定 UV → _uvpm_repack(现在:margin + 旋转 + 启发式搜索)→ 抽 UV 几何 → export
```
## 错误处理
| 失败点 | 处理 |
|---|---|
| UVPM 某属性名不存在(版本差异) | `_uvpm_set` 记警告、跳过该属性,其余照设、pack 照跑 |
| UVPM 启用/pack 整体失败 | 现有 `_uvpm_repack` try/except:记警告、`_uvpm_failed=True`、回退内置 pack(行为不变) |
| 启发式耗时过长 | 由 `UVPM_HEURISTIC_TIME` 上限约束 |
原则:排布增强单点失败降级,不影响主流程与 FBX 产出。
## 测试与验证
1. **现有单测不回归**`python -m unittest tests.test_bl_decimate tests.test_uv_preview tests.test_unity_assets`(本改动无纯函数,主要确认无破坏)。
2. **端到端(主验收)**`python model_decimate.py src/gargoyle.fbx --tris 3000 --max-overlap 0.15`,对比基线(seam@45 / 390 岛 / **利用率 52.3%** / 翻转 0% / 重叠 13.3%):
- 利用率**明显上升**
- 岛数不变(排布不改岛数)、翻转仍 0%、重叠仍 ≤ 门限;
- 记录 pack 耗时增量;
- Read 观察图确认薄条更紧、黑块变少。
3. **回归**`python model_decimate.py src/well1500.fbx --tris 5000`(正常走 seam@66 的模型)确认排布增强不破坏,流程不崩、产物正常。
## 验收标准
- gargoyle 3000`--max-overlap 0.15`):UV 利用率明显高于 52.3%;岛数/翻转/重叠不退化。
- 属性名不匹配时降级不崩、仍出 UVPM 排布(或内置兜底)。
- well1500 回归正常。
- 现有单测全绿。
## 实现注意
- 属性名/取值一律以第 1 节探针结论为准;spike 未确认前不写死具体名。
- `_uvpm_set``hasattr` 守卫是关键:防止版本差异把整个 UVPM 排布拖垮。
- 若探针发现启发式需要非 `'0'``pack_op_type` 或专门 `mode_id`,在计划中据实调整并在 README 注明。
## 实现修订(2026-07-21,系统调试后)
实现中发现 **UVPM 启发式搜索在 headless 下会随机崩溃引擎进程**`Error: Engine process died unexpectedly`):well1500 崩 3/3、gargoyle 崩 1/2(同模型重跑结果不一致),旋转步进无辜。启发式因此不可靠、且使输出非确定。
**最终落地**:弃用启发式,只保留 `rotation_step=15`(稳定、零崩溃、确定性)。实测利用率提升较小但可靠——gargoyle 3000`--max-overlap 0.15`52.3%→**55.6%**well1500 5000 稳定 `+uvpm`。移除 `_uvpm_pack_once`/重试与 `UVPM_HEURISTIC_TIME``_uvpm_repack` 回到单次 UVPMrotation 15)。验收从"明显上升"下修为"稳定小幅上升且零崩溃/确定性"。