Files
AIC-Project/docs/superpowers/specs/2026-07-23-quad-reducer-retopo-upgrade-design.md
T
2026-07-23 15:09:24 +08:00

6.7 KiB
Raw Blame History

--reducer quad 升级为可靠四边重拓扑 设计

日期:2026-07-23

背景与动机

真机排查(gargoyle 500k、supergirl 1M)确认了现有 --reducer quad 的三个问题:

  1. 高密度输入必破洞:QR 引擎从很高密度网格(500k~1M 面)激进减面时,非确定性地打出 孔洞/非流形边,水密门(零容忍)几乎总判破损 → 回退 collapse。实测把高模先 collapse 到 中等密度(~50k) 再喂 QR,输出即干净。
  2. 导出前被三角化bl_decimate.main 在 quad 成功路径也调 _triangulate,导致"quad 后端" 的 FBX 里其实是三角面,四边拓扑被毁——与"要四边"矛盾。
  3. 零容忍门太严:有机角色(supergirl)QR 常只留 1 个薄部位小洞(约 3 开边),门把这个 近乎干净的 QR 一票否决。补掉小洞即净。

用户决定:改造现有 --reducer quad,把"预 collapse + QR + 补小洞 + 保四边"整套配方内建, 让 quad 后端真正可用。collapse 后端与默认值(quad)不变。

约束

  • 不加外部依赖。
  • collapse 后端行为零变化--reducer 默认仍为 quad
  • QR 任何灾难性失败仍自动回退 collapse,绝不中断(保留现有回退契约)。
  • 不 stage 用户脏工作区(Unity/src/产物)。
  • 纯策略(cap 判断、软门)与 Blender 操作分离,纯逻辑 TDD。

新流程(--reducer quad

bl_decimate.main() 的 quad 分支改为:

  1. 预 collapse_clean_mesh + _triangulate 后,若面数 > qr_input_cap(默认 50000)_decimate 到 cap + _triangulate;≤ cap 则跳过。给 QR 一个不炸洞的中等密度输入。
  2. QR 重拓扑_remesh_quad 导出预处理网格 → xremesh.exe(ExactQuadCount=1 目标 tris_to_target_quads(--tris) 四边)→ 导回。
  3. 补小洞QR 导回后 fill_holes(sides <= QR_HOLE_MAX_SIDES=6),补掉薄部位零星小洞。
  4. 软水密门:补洞后比对输入基线——topology_acceptable(src_b, src_nm, out_b, out_nm, tol=QR_CATASTROPHIC_TOL)out_b <= src_b + tol and out_nm <= src_nm + tol 则接受 (保留四边);否则判灾难性破碎,弃用 QR 回退 collapse(标 quad->collapse)。
  5. 保四边导出quad 成功路径不再 _triangulate_do_unwrap 与导出直接作用于四边网格 (FBX/Cycles 烘焙/Unity 均支持四边;Unity 导入自动三角化)。

collapse 路径与 quad->collapse 回退路径仍三角化(collapse 本就产三角)。

架构与接口

qr_bridge.py(纯逻辑,不 import bpy

  • 常量:QR_INPUT_CAP = 50000QR_HOLE_MAX_SIDES = 6QR_CATASTROPHIC_TOL = 12
  • 修改 topology_acceptable(src_boundary, src_nonmanifold, out_boundary, out_nonmanifold, tol=0):加 tol 参数(默认 0,向后兼容现有调用/测试),判定改为 out_boundary <= src_boundary + tol and out_nonmanifold <= src_nonmanifold + tol
  • 新增 precollapse_target(face_count, cap=QR_INPUT_CAP) -> int | Noneface_count > cap 返回 cap,否则 None(跳过预 collapse)。

bl_decimate.pyBlender 内)

  • 新增 _fill_small_holes(obj, max_sides):编辑模式全选 → bpy.ops.mesh.fill_holes(sides=max_sides) → 回物体模式。异常降级不中断。
  • 修改 _remesh_quad(obj, target_tris, warnings):导回 retopo 后 (a) _fill_small_holes(retopo, qr_bridge.QR_HOLE_MAX_SIDES) (b) 用软门 topology_acceptable(..., tol=QR_CATASTROPHIC_TOL) 判定; (c) 接受则删原 obj、retopo 设为 active、return True(不三角化);拒绝则弃 retopo、 恢复 obj 选中态、return False。其余(引擎发现/子进程/轮询/选择态恢复)不变。
  • 修改 main()
    • 解析 qr_input_cap = int(argv[6]) if len(argv) > 6 else QR_INPUT_CAP
    • quad 分支:_remesh_quad 前按 precollapse_target 预 collapse;成功后去掉 _triangulate(obj)(保四边)。orig(tris_before)仍取预 collapse 前的高模面数。

model_decimate.pyCLI

  • --qr-input-cap(type intdefault QR_INPUT_CAP),透传为 Blender argv 第 7 位(index 6)。
  • 校验 > 0。摘要打印沿用(后端 已有)。

数据流

FBX --import--> join --clean--> triangulate --orig
  reducer=quad:
    面数 > cap? --yes--> collapse 到 cap --triangulate
    _remesh_quad: export --xremesh(exact)--> retopo --import
      fill_holes(<=6) --> 软门(tol) 过? --yes--> 保留四边(不三角化)
                                       --no--> 弃用, 回退 collapse(三角)
  reducer=collapse 或 quad->collapse: decimate 循环(三角)
--> _do_unwrap(smart/seam) --> export(四边或三角) + MT_SUMMARY{reducer,...}

错误处理

情况 处理
引擎缺失/超时/报错/无输出/导回无 mesh warning,回退 collapse(现有)
fill_holes 异常 warning,跳过补洞,继续走软门
补洞后仍灾难性破损(超 tol) warning,弃 QR 回退 collapse
预 collapse 后 QR 仍失败 回退 collapse(在已预collapse的网格上继续减到目标)

回退后 reducerquad->collapse,绝不中断。

已知取舍

  • 预 collapse 会在 QR 前损失部分细节 → 低模形状比"直接 QR"略有偏差(实测形变从 ~0.015% 升到 ~0.06%,量级仍很小)。烘焙细节来自原始高模(model_bake 用 high FBX),故低模这点 偏差对最终贴图影响小;换来的是 QR 不破洞、能保四边。取舍值得。
  • 补洞产生的少量 n-gon 补丁(≤6 边)与 QR 偶发三角使输出"以四边为主",非 100% 纯四边。

测试

  • tests/test_qr_bridge.py
    • topology_acceptabletol(0,0,3,0,tol=12)->True(0,0,13,0,tol=12)->False、 默认 tol=0(0,0,1,0)->False(现有语义不变)。
    • precollapse_target(1000000,50000)->50000(40000,50000)->None、边界 (50000,50000)->None
  • 回归python -m unittest discover -s tests 全绿(现有测试含 topology_acceptable 旧调用 仍按 tol=0 通过)。
  • 真机 smoke
    • model_decimate supergirl.fbx --tris 10000 --reducer quadbackend=quad、输出以四边为主 (quad 数 >> tri)、开边/非流形 ≤ 输入基线+tol、有 UV。
    • gargoyle.fbx --tris 10000 --reducer quad:同上或合理 quad->collapse
    • --reducer collapse 回归:面数、拓扑与升级前一致(零变化)。
    • 强制回退(QR_ENGINE 指错)quad->collapse、输出正常。

明确不做(YAGNI

  • 不做硬边引导/直边保真(实测无效,另属课题)。
  • 不暴露 fill-holes sides、catastrophic tol 为 CLI(内置常量足够;只暴露 --qr-input-cap)。
  • 不改 model_bake/model_translator(四边低模它们已支持)。
  • 不追求 100% 纯四边(少量 n-gon/tri 可接受)。