ModelTranslator: document QR quad remesh backend
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b8eb40f3e4
commit
ac99d104c0
@@ -0,0 +1,137 @@
|
||||
# ModelTranslator 减面可选后端 Quad Remesher 设计
|
||||
|
||||
日期:2026-07-22
|
||||
|
||||
## 背景与动机
|
||||
|
||||
现有减面管线 `model_decimate.py` → `bl_decimate.py` 用 Blender 原生
|
||||
**DECIMATE(COLLAPSE)** modifier 按 `--tris` 目标三角面数减面。用户不满的核心痛点:
|
||||
|
||||
1. **拓扑乱 / 碎三角**:COLLAPSE 产出狭长不规则三角,影响着色、变形、法线。
|
||||
2. **UV 展开难**:碎三角导致 seam/UV 岛碎、利用率低。
|
||||
|
||||
用户已安装 **Quad Remesher(Exoside,重打包版)** Blender 插件,可产出规整四边拓扑,
|
||||
从根子上改善以上两点。本设计将其作为**可选减面后端**接入,默认不改变现有行为。
|
||||
|
||||
## 关键技术结论(已 spike 验证)
|
||||
|
||||
`bpy.ops.qremesher.remesh()` 是 **modal 操作符**(`modal_handler_add` + timer,返回
|
||||
`RUNNING_MODAL`)。`blender -b` 后台无事件循环,modal 永不触发,结果 FBX 永不导回——
|
||||
**直接调操作符在 headless 必然失败**(与 UVPM headless 崩的教训同类)。
|
||||
|
||||
真正的重活是**解耦的外部引擎进程**:插件只是"桥",做导出 FBX → 写 settings →
|
||||
跑 `Engine/xremesh.exe -s settings.txt` 子进程 → 轮询 `progress.txt` → 导回 retopo。
|
||||
本设计**自己重实现这 ~40 行桥胶水**,完全确定、后台安全、不依赖 modal、不受
|
||||
`--factory-startup` 影响、不需 enable 插件。
|
||||
|
||||
**Spike 实测**:icosphere 5120 tris → `TargetQuadCount=500` → 0.7s 出 441 面全 quad,
|
||||
exit 0、progress=2;重打包版无许可问题能直接跑。
|
||||
|
||||
## 约束
|
||||
|
||||
- 不加外部依赖(纯标准库 + bpy)。
|
||||
- 不覆盖输入 FBX;只在生成的 `_low.fbx` 输出重拓扑数据。
|
||||
- 现有 CLI/输出目录/命名/`collapse` 路径行为**零变化**(`--reducer` 默认 `collapse`)。
|
||||
- QR 失败(引擎缺失/超时/负值/导回空)一律记 warning 并**回退 collapse,绝不中断**——
|
||||
与现有 UVPM"失败即回退"同哲学。
|
||||
- 面数口径:`target_quads = tris // 2`,接受 QR 近似输出(约 ±20%),不做二次 collapse
|
||||
(二次 collapse 会重新引入碎三角,抵消 QR 好处)。**用 `ExactQuadCount=1` 尊重目标数**
|
||||
——真机验证发现自适应模式(`ExactQuadCount=0`)在高细节硬表面模型上面数暴涨数倍
|
||||
(well1500 目标 2500→11500 quads)并连带 seam 展开重叠爆炸,故禁用自适应。
|
||||
- `QR_ENGINE` 覆盖为**权威**语义:显式设了就以它为准,无效路径即视同缺失走 collapse 回退
|
||||
(不再静默自动发现,保证回退契约可测)。
|
||||
|
||||
## 架构
|
||||
|
||||
分三层,纯逻辑与 Blender 操作分离,便于 TDD:
|
||||
|
||||
### 1. 新增纯模块 `qr_bridge.py`(不 import bpy)
|
||||
|
||||
| 函数 | 职责 |
|
||||
|---|---|
|
||||
| `find_qr_engine() -> str \| None` | 按标准 addon 路径查 `xremesh.exe`,找不到返回 None |
|
||||
| `tris_to_target_quads(tris) -> int` | `max(1, tris // 2)`;1 quad ≈ 2 tris |
|
||||
| `build_settings(in_fbx, out_fbx, prog, target_quads, *, adaptive=50, exact=False, hard_edges=True) -> str` | 生成 `RetopoSettings.txt` 文本(HostApp/FileIn/FileOut/ProgressFile/TargetQuadCount/CurvatureAdaptivness/ExactQuadCount/AutoDetectHardEdges 等) |
|
||||
| `parse_progress(text) -> (state, msg)` | `state ∈ {"running","success","error"}`;首行 `2`=success,`<0`=error(次行为文本),空/其它=running |
|
||||
|
||||
`find_qr_engine` 搜索顺序:`QR_ENGINE` 环境变量 → `%APPDATA%/Blender Foundation/Blender/*/scripts/addons/QuadRemesher/Engine/xremesh.exe`。
|
||||
|
||||
### 2. `bl_decimate.py` 新增 `_remesh_quad(obj, target_tris, warnings) -> bool`
|
||||
|
||||
Blender 内执行,步骤:
|
||||
|
||||
1. `find_qr_engine()`;None → warning,return False。
|
||||
2. 建工作目录(`tempfile.gettempdir()/mt_qr/`),清旧 `retopo.fbx`/`progress.txt`。
|
||||
3. 选中 `obj`,`bpy.ops.export_scene.fbx(use_selection=True)` 导出 `inputMesh.fbx`。
|
||||
4. `build_settings(...)` 写 `RetopoSettings.txt`(`hard_edges=True`,`exact=False`)。
|
||||
5. `subprocess.Popen([engine, "-s", settings])`,阻塞轮询 `progress.txt`(间隔 0.3s,
|
||||
超时默认 **120s**):
|
||||
- `parse_progress` → `success` 且 `retopo.fbx` 非空 → 进入 6;
|
||||
- `error` / 超时 / 进程退出但无输出 → warning,return False。
|
||||
6. 记录旧对象集合 → `bpy.ops.import_scene.fbx(retopo.fbx)` → 删除原 `obj`,把导回的
|
||||
mesh 设为新 active object(供后续展 UV/导出复用)。return True。
|
||||
|
||||
**任何异常都被捕获 → warning → return False**,不抛出。
|
||||
|
||||
### 3. `main()` 分流
|
||||
|
||||
- 解析第 5 个 argv `reducer`(`"collapse"`(默认)/`"quad"`)。
|
||||
- 流程:
|
||||
- `_clean_mesh(obj)`(现有)
|
||||
- `reducer == "quad"` 且 `_remesh_quad()` 成功 → **跳过 DECIMATE**,记 `reducer="quad"`;
|
||||
否则(或 QR 失败回退)走现有 `_triangulate` + collapse 循环,记 `reducer="collapse"`
|
||||
或 `"quad->collapse"`。
|
||||
- 之后照旧:`_do_unwrap`(在更干净的拓扑上展 UV)→ 三角化保证导出为三角 → 导出。
|
||||
- `MT_SUMMARY` 加 `reducer` 字段。
|
||||
|
||||
> 注:QR 输出为 quad,展 UV 在 quad 上进行(seam 更干净);导出前需确保三角化
|
||||
> (复用现有 `_triangulate`),使 `_low.fbx` 仍为三角网格,兼容下游烘焙。
|
||||
|
||||
### 4. `model_decimate.py` CLI
|
||||
|
||||
- 加 `--reducer {collapse,quad}`,`default="collapse"`,透传给 Blender argv 第 5 位。
|
||||
- 打印实际后端与面数:`后端=quad 面数 20000 -> 882`(或 `quad->collapse` 回退提示)。
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
FBX --import--> join --clean--> [reducer 分流]
|
||||
quad: export inputMesh.fbx --xremesh.exe--> retopo.fbx --import--> 全 quad obj
|
||||
collapse: DECIMATE(ratio) 循环
|
||||
--> _do_unwrap(seam+UVPM) --triangulate--> export _low.fbx + MT_SUMMARY{reducer,...}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 情况 | 处理 |
|
||||
|---|---|
|
||||
| 找不到 xremesh.exe | warning,回退 collapse |
|
||||
| 引擎超时(>120s) | kill 进程,warning,回退 collapse |
|
||||
| progress 负值(含无许可/EULA 的 -2) | warning(带引擎文本),回退 collapse |
|
||||
| 进程退出但 retopo.fbx 空/缺 | warning,回退 collapse |
|
||||
| 导回 FBX 无 mesh | warning,回退 collapse |
|
||||
|
||||
回退后 `reducer` 字段标 `quad->collapse`,用户可从摘要看出实际走了哪条路。
|
||||
|
||||
## 测试
|
||||
|
||||
- **`tests/test_qr_bridge.py`**(纯函数,TDD):
|
||||
- `tris_to_target_quads`:偶/奇/极小值(`1→1`, `10000→5000`, `1→1`)。
|
||||
- `build_settings`:含关键行、路径转义、`exact`/`hard_edges` 开关映射正确。
|
||||
- `parse_progress`:`"2"`→success、`"-3\n失败"`→error 带文本、`""`/`"0.5"`→running。
|
||||
- `find_qr_engine`:环境变量优先、缺失返回 None(用临时目录构造)。
|
||||
- **回归**:`python -m unittest discover -s tests` 全绿(现有测试不受影响)。
|
||||
- **真机 smoke**:
|
||||
- `python model_decimate.py src/well1500.fbx --tris 5000 --reducer quad -o out_qr`
|
||||
→ 输出存在、`reducer=quad`、面数近似 5000(±20%)、UV 岛数/翻转/重叠 打印。
|
||||
- 与 `--reducer collapse`(默认)对比 UV 指标,确认岛数下降/更规整。
|
||||
- 强制回退验证:临时改 `QR_ENGINE` 指向不存在路径 → `reducer=quad->collapse`、
|
||||
仍正常出 `_low.fbx`。
|
||||
|
||||
## 明确不做(YAGNI)
|
||||
|
||||
- 不改烘焙 `bl_bake.py`(QR 只作用于减面产出的低模)。
|
||||
- 不做二次 collapse 卡精确面数。
|
||||
- 不暴露 QR 全部参数(对称/顶点色/材质引导);只用 target/adaptive/hard_edges 合理默认。
|
||||
- 不动进行中的 `2026-07-16-model-bake-quality-optimization` 计划;本功能与其正交,
|
||||
可后续叠加(quad 拓扑 + 法线修复不冲突)。
|
||||
Reference in New Issue
Block a user