FullPart 第四例:折叠台灯 —— 根因找到并修复(细杆 90° 之谜:退化盒在 16³ 条件网格里薄维不足一格)
EPPUR · 2026-06-27 · PNM Lamp 13928(5 件,4 revolute 串联链)· 含三次被用户当场纠错后,最终把根因查到底并验证修复
★ 最终结论(根因+修复,均经因果实验验证)。那根上臂杆生成转 90° 的根因:FullPart 把每个 part 在一个边长=盒子最长边、16³ 的立方体网格里条件化+放置,盒子的薄/厚只靠"哪些格点在盒内"的 mask 传进去。part0 盒子 aspect=41,最薄维(x)在该网格里只有 0.39 个体素(不足一格) → "x 是薄轴、z 才是长轴"这条朝向信息被分辨率抹掉 → 模型瞎猜朝向 → 错。阈值:aspect≳16(薄维<1格)即危险。
修复:prep 时把退化薄维加厚到 aspect≤8(薄维≥2 格)。验证:同图同件,把 part0 盒子 aspect 41→8 后,长轴从错的 x 纠正为对的 z;整把灯零对齐原样加载即连(part0 两侧缝 0.261/0.399 → 0.046/0.002)。
修复前后(side+X,按件着色)。左=原盒:红 part0 横着浮空、断开。中=加 aspect 护栏:红上臂斜着把黄下臂↔蓝连杆↔绿灯头连起来。右=修复后 3/4:一把连好的折叠灯。全程零关节对齐,纯靠把退化盒加厚让生成出对的朝向。
因果实验(顶视图,只生成 part0):A=原盒(aspect41,薄维0.39格)→生成一团乱/长轴 x=错;B=把 x 加厚(aspect3.9,薄维4格)→长轴 z=对。只改盒子薄维一项,朝向就从错变对 → 坐死因果。
诚实过程记录(我被纠错三次才查到底):❌"只是关节处不咬合" → ❌"pivot-snap 就连上了"(循环度量+搬坏件) → ❌"复杂链连不上 / 关节对齐是缺口"。用户一句"接关节为什么用 bbox、该用 mesh+关节"点破。最终用最直接的量(相邻件 mesh 距离 + 生成件 vs GT mesh 直比 + 受控重生成)才查到上面的真根因。下面保留更正过程。
更正后的结论:5 件里有 1 件(最细的臂杆)生成成了错朝向、戳出盒子 40 倍 → 链断了
查每个生成件的几何 bound vs 它的输入盒子,part0(上臂细杆)严重不符:输入盒子是"x 最薄(0.018)、z 最长(0.71)"的细杆盒,生成出来却是沿 x 方向 0.70 长、把盒子在 x 上撑爆 40 倍的横杆(fill% x=40.4,y/z≈0)——朝向转了 90°。其余 4 件(连杆/灯头/下臂/底座)都老实填满各自盒子(fill≈1.0)。
坐实 bug:红=生成件,蓝=它的输入盒子。左 part0 上臂:红杆沿 x 横穿、戳出薄盒两头,朝向完全错。右 part3 下臂:红杆正确躺在盒子里。同一个模型,只有最细/最接近退化的盒子(薄板状)失败了。
(作废)我之前声称"pivot-snap 连上了"的图——其实没连上:左 BEFORE 那根水平红杆就是被生成错的 part0;右 AFTER 是我用循环度量(snap 把"子件离 pivot 最近点"移到"父件最近点",再去量这俩点的距离,当然≈0)+ 搬动一个本就坏掉的件,结果灯头(绿)和红杆穿插成一团。这张图证明不了连接,已作废。
为什么前三例没暴露、这例暴露了
FullPart 只拿到每个 part 的轴对齐包围盒(AABB)。前三例(门/抽屉/马桶)的部件都大致轴对齐,盒子不退化,生成都对。台灯的臂是斜细杆,它的 AABB 是一块很薄的板(最薄方向 0.018)——这种近退化的薄盒,模型无法从 AABB 推出"杆其实是斜着的",就按某个默认朝向生成,结果朝向错、撑爆盒子。这是 FullPart 在细/斜/退化部件上的真实失败模式。
★ 第三次更正(用户再纠):拼装根本不需要 bbox,好的关节零处理就贴合;问题只在 part0 一根杆
用户指出:接关节就该用部件 mesh + 关节,跟 bbox 没关系。完全正确。我老实量了相邻件 mesh 的最近顶点距离(原样加载、零对齐、不碰 bbox):底座↔下臂 0.001、连杆↔灯头 0.001(贴合);下臂↔上臂 0.261、上臂↔连杆 0.399(缝)。不涉及 part0 的两个关节零处理就贴在一起——证明拼装不需要任何对齐/bbox(我之前的 pivot-snap 是无中生有,彻底撤回)。仅有的两条缝都挂在 part0(那根转了 90° 的上臂杆)身上,是它够不着上下邻件。
用mesh 直接比对(非 bbox):GT link_0(绿)vs 生成 part0(红),同坐标轴。顶视图(下排)决定性:GT 杆沿 z(南北),生成杆沿 x(东西),垂直,差 90°。中心对得上,纯是朝向转了。
原样加载全部 5 件(零处理)。左上 3/4、左下 front+Z 都是一把正常的折叠灯(part0 偏转被挡住看不出);右下 side+X 才露出 part0 造成的缝。
难度阶梯(更正版)
| 例子 | 关节 | part 生成 | 整体 |
| 微波炉门 | 单 revolute | ✅ 各件填满盒子 | ✅ 门盖住机身腔口 |
| 三抽屉柜 | 3 prismatic 并联 | ✅ 各件填满盒子 | ✅ 抽屉滑进柜格 |
| 马桶 | 多 revolute 曲面 | ✅ 曲面/非凸件 | 🟡 盖/座圈盒重合→长得像 |
| 折叠台灯 | 4 revolute 串联链 | 🟡 3/5 件完美;仅 part0 细斜杆转 90° | 🟡 2/4 关节零处理 0.001 贴合;2 条缝全因 part0 |
对主线的真实启示(精确版):① 拼装不需要 bbox/对齐——好的关节原样加载就 0.001 贴合,接关节是 mesh 本身的事;② 这例既不是"链连不上",也不是"对齐难",而是 单独一根细斜杆(退化薄盒)生成偏了 90°,它一个人造成了仅有的两条缝;③ part0 要是生成对了,原样加载就是连好的灯,一步对齐都不用。所以 FullPart 的真实边界是:细/斜/退化盒部件的几何生成偶发失败(AABB 编码不了斜向细长结构)——修它要 (a) 给比 AABB 更强的朝向约束(OBB/方向),或 (b) 重生成那一件。之前"关节对齐是缺口""复杂链连不上"两种说法都撤回。
仍然成立的部分
前三例(
微波炉门 /
三抽屉柜 /
马桶)的结论不受影响:在
盒子不退化(部件大致轴对齐)时,给定 part 盒子,FullPart 能把各件(含厚门、开口抽屉、曲面非凸件)干净生成成独立全分辨率 part。台灯这例补充了边界:
斜细杆/退化盒会失败。
资产 PNM Lamp 13928 · 诊断脚本 /tmp/lamp_bug.py(生成件 bound vs 输入盒) · 报告 EPPUR/experiments/fullpart_20260627/REPORT_FullPart微波炉_20260627.md