ModelTranslator: README/spec/plan 记录 UVPM 弃用启发式、只留旋转15°

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
ud18010
2026-07-21 16:18:56 +08:00
co-authored by Claude Opus 4.8
parent 4f18c770c1
commit 6087ce3598
3 changed files with 11 additions and 1 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ python model_bake.py src/well1500.fbx src/well1500_low.fbx # -> out_bake/well1
python model_translator.py out_bake/well1500/well1500.fbx # -> out/well1500/Unity 资源) python model_translator.py out_bake/well1500/well1500.fbx # -> out/well1500/Unity 资源)
``` ```
- **model_decimate.py**:多 mesh 自动 join;**减面前清理网格**(按局部包围盒对角线相对焊接重合点 + 去退化面,给 collapse 更干净的流形、减少被迫加的 seam);三角化后 Decimate(collapse) 减到 `--tris`(±3%,最多 2 轮修正);旧 UV 全删后重展——默认锐边 seam 整岛展开(SLIM 展开后 `minimize_stretch` 松弛 + `average_islands_scale` 纹素均衡),质量门不达标(翻转 >2% 或重叠 >8%)先按更低 seam 角度扫描(55/45/35°)取过门且岛数最少者抢救,全失败才回退 Smart UV Project`--unwrap smart` 可直接选投影式展开;**`--max-overlap 0.15` 放宽重叠门限**,让更高 seam 角度(岛更少)能过门被选中——岛数优先、可接受略高重叠时用(翻转门限始终严格);排布默认用 UVPackmaster 4 重排(只在最终选定 UV 上跑一次),UVPM4 不可用自动沿用内置 pack_islands 布局;输出 `<名>_low.fbx``-o` 改目录)与 `<名>_low_uv.png`(UV 线框观察图,便于人工查阅切分/排布/碎岛——Blender 抽 UV 几何,系统 Python 用 Pillow 绘制,因 headless 无 GPU 无法用 Blender 直接出 PNG),日志报 UV 岛数/利用率与实际生效的 seam 角度 - **model_decimate.py**:多 mesh 自动 join;**减面前清理网格**(按局部包围盒对角线相对焊接重合点 + 去退化面,给 collapse 更干净的流形、减少被迫加的 seam);三角化后 Decimate(collapse) 减到 `--tris`(±3%,最多 2 轮修正);旧 UV 全删后重展——默认锐边 seam 整岛展开(SLIM 展开后 `minimize_stretch` 松弛 + `average_islands_scale` 纹素均衡),质量门不达标(翻转 >2% 或重叠 >8%)先按更低 seam 角度扫描(55/45/35°)取过门且岛数最少者抢救,全失败才回退 Smart UV Project`--unwrap smart` 可直接选投影式展开;**`--max-overlap 0.15` 放宽重叠门限**,让更高 seam 角度(岛更少)能过门被选中——岛数优先、可接受略高重叠时用(翻转门限始终严格);排布默认用 UVPackmaster 4 重排(只在最终选定 UV 上跑一次,旋转步进调细到 15° 以利薄斜条对齐提升利用率;UVPM 启发式搜索在 headless 下会随机崩溃引擎故未启用),UVPM4 不可用自动沿用内置 pack_islands 布局;输出 `<名>_low.fbx``-o` 改目录)与 `<名>_low_uv.png`(UV 线框观察图,便于人工查阅切分/排布/碎岛——Blender 抽 UV 几何,系统 Python 用 Pillow 绘制,因 headless 无 GPU 无法用 Blender 直接出 PNG),日志报 UV 岛数/利用率与实际生效的 seam 角度
- **model_bake.py**Cycles selected-to-active 烘焙。normal(切线空间 OpenGL +Y/ao 直接烘;color/metallic/roughness 把高模 Principled 对应输入接 Emission 烘 EMIT。`--size` 默认 2048`--samples` AO 采样默认 64,射线距离默认低模包围盒对角线 2%(`--ray-distance` 覆盖);低模无 UV 会报错,高低模包围盒差超 10% 打警告;导入后自动应用物体变换——未应用缩放的 FBX(如 cm 单位导出的 scale=0.01)会把射线距离缩到近零导致大面积烘空(脏色);固定 `-t 1` 单线程跑 Blender——5.0 的 selected-to-active 射线求交多线程有竞争,会随机 EXCEPTION_ACCESS_VIOLATION 崩溃 - **model_bake.py**Cycles selected-to-active 烘焙。normal(切线空间 OpenGL +Y/ao 直接烘;color/metallic/roughness 把高模 Principled 对应输入接 Emission 烘 EMIT。`--size` 默认 2048`--samples` AO 采样默认 64,射线距离默认低模包围盒对角线 2%(`--ray-distance` 覆盖);低模无 UV 会报错,高低模包围盒差超 10% 打警告;导入后自动应用物体变换——未应用缩放的 FBX(如 cm 单位导出的 scale=0.01)会把射线距离缩到近零导致大面积烘空(脏色);固定 `-t 1` 单线程跑 Blender——5.0 的 selected-to-active 射线求交多线程有竞争,会随机 EXCEPTION_ACCESS_VIOLATION 崩溃
- 输出命名 `<名>_color/normal/metallic/roughness/ao.png`,正好命中转换器的纯网格贴图命名约定 - 输出命名 `<名>_color/normal/metallic/roughness/ao.png`,正好命中转换器的纯网格贴图命名约定
@@ -259,3 +259,7 @@ Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
- **占位符**:探针脚本、`_uvpm_set`、常量、各命令均为完整内容。属性名标注"以 Task 1 为准"是 spike-first 设计的必要性质(执行时由 Task 1 输出定稿),非未决占位——`hasattr` 守卫保证即便名字有出入也不崩,Task 3 Step 2 的"属性不存在"警告会兜住并要求回改。 - **占位符**:探针脚本、`_uvpm_set`、常量、各命令均为完整内容。属性名标注"以 Task 1 为准"是 spike-first 设计的必要性质(执行时由 Task 1 输出定稿),非未决占位——`hasattr` 守卫保证即便名字有出入也不崩,Task 3 Step 2 的"属性不存在"警告会兜住并要求回改。
- **类型/命名一致**`_uvpm_set(p, name, value, warnings)`Task 2 Step 2 定义,Step 3 调用一致);常量 `UVPM_ROTATION_STEP`/`UVPM_HEURISTIC_TIME`Task 2 Step 1 定义,Step 3 使用一致);`p``scene.uvpm4_props.default_main_props`(与现有 `_uvpm_repack` 一致)。 - **类型/命名一致**`_uvpm_set(p, name, value, warnings)`Task 2 Step 2 定义,Step 3 调用一致);常量 `UVPM_ROTATION_STEP`/`UVPM_HEURISTIC_TIME`Task 2 Step 1 定义,Step 3 使用一致);`p``scene.uvpm4_props.default_main_props`(与现有 `_uvpm_repack` 一致)。
- **已知风险**UVPM4 属性名/取值由 Task 1 探针定;启发式若需特定 `pack_op_type` 在 Task 2 据实调整;薄条几何天然限制上限,验收以"明显上升"而非硬数字(spec 一致)。 - **已知风险**UVPM4 属性名/取值由 Task 1 探针定;启发式若需特定 `pack_op_type` 在 Task 2 据实调整;薄条几何天然限制上限,验收以"明显上升"而非硬数字(spec 一致)。
## 执行修订(2026-07-21
Task 3 端到端验证暴露:**UVPM 启发式在 headless 下随机崩溃引擎**well1500 3/3、gargoyle 1/2)。经 systematic-debugging 确认根因为 heuristicrotation 无辜),且崩溃非确定。用户裁定:**弃用启发式,只留 rotation_step=15**。`_uvpm_repack` 移除重试/启发式,回到单次 UVPM(rotation 15)。最终:gargoyle 52.3→55.6%、well1500 稳定 +uvpm,零崩溃、确定性。
@@ -105,3 +105,9 @@ _uvpm_set(p, "heuristic_search_time", UVPM_HEURISTIC_TIME, warnings)
- 属性名/取值一律以第 1 节探针结论为准;spike 未确认前不写死具体名。 - 属性名/取值一律以第 1 节探针结论为准;spike 未确认前不写死具体名。
- `_uvpm_set``hasattr` 守卫是关键:防止版本差异把整个 UVPM 排布拖垮。 - `_uvpm_set``hasattr` 守卫是关键:防止版本差异把整个 UVPM 排布拖垮。
- 若探针发现启发式需要非 `'0'``pack_op_type` 或专门 `mode_id`,在计划中据实调整并在 README 注明。 - 若探针发现启发式需要非 `'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)。验收从"明显上升"下修为"稳定小幅上升且零崩溃/确定性"。