SNAP3D:怎么让 AI 生成的 3D 零件真正拼起来?

为什么"看起来像"不等于"装得上"?

把一张办公椅的照片丢给今天的 3D 生成模型,它能还给你一把椅子,甚至是一把拆成五六个部件的椅子。但真要把这些部件拼回去,问题马上就来了:两条椅腿占进了同一块空间,两个零件之间没有任何能扣住对方的地方,松开手的一瞬,整把椅子散成一地。

这不是某个模型的失误,而是这一类模型的通病。SNAP3D(arXiv:2609.13146,卡内基梅隆大学团队)给这个缺口起了一个正式的名字:physically unrealizable,物理上不可实现。意思是单个零件单独看都完整、都漂亮,但拼到一起时,要么互相穿透(interpenetrate,两个零件占同一块空间),要么缺少有效连接,要么在重力下垮掉。SNAP3D

这个缺口有多严重,量化一下最直观。论文让三个主流的 part-aware generator 和自己对着同一批输入比赛。所谓 part-aware generator,指能从一张图直接交出一组已分解零件 mesh 的零件级生成器。在统一的物理测试里,X-Part 的稳定率是 0.0%,OmniPart 是 2.0%,PartCrafter 是 1.0%,SNAP3D 自己是 95.0%。稳定率的含义是把生成的装配体放回原物位置、松手,它还能站在原地不垮。换句话说,之前那些"看起来像"的零件,几乎没有一件真正立得住。讽刺的是,X-Part 的几何保真度恰是三个基线里最高的一个,精度最高的模型反而连一次稳定都做不到。SNAP3D

为什么偏偏是现在暴露这个缺口?因为零件级的单图生成这几年确实跑起来了,PartCrafter、UniPart 这类方法能从一张 RGB 图直接端出一组语义清晰的零件,HoloPart 这类 amodal 补全路线则先在 3D 几何上分割、再补全成完整零件。下游的动画、仿真、3D 打印立刻遇到了"拿到手却装不上"的尴尬。而这些方法的目标函数里,从头到尾没有"物理"两个字。HoloPart 做的是 amodal 补全,专攻把被遮挡的部分补完整,补完的相邻零件可以各占各的区域,边界归谁它不管,物理可行性不在它的字典里;HoloPartPhysPart 则走了另一条支线,关心零件装上去之后能不能动(articulation,铰链滑轨那种可动连接),而不是整个装配体能不能站稳,它连"零件之间的连接"都没有建模。PhysPart

"好不好看"和"装不装得上",在这条技术线里一直是被混为一谈的两件事。同一张输入图下,差别具体长什么样,看这组对比:

SNAP3D 与三个基线的定性对比

图注:同一批输入图下,X-Part、OmniPart、PartCrafter 与 SNAP3D(最下行 Ours)的零件拼装渲染;红色标注的是零件之间相互穿透(interpenetration)的曲面区域。基线各行在接触面有大片红色,SNAP3D 一行基本干净。红色是论文刻意画上的穿透可视化,不是算法 bug。SNAP3D

基线行红成一片、自己那行干干净净,这个视觉差就是整篇论文的起点。SNAP3D 接下来的全部工作,都围绕一个问题展开:把"好看"和"能装"拆开之后,物理那部分到底由谁来负责?

为什么把物理放在生成之后,而不是生成之中?

SNAP3D 的整条管线,一句话就能说清:上游的 part-aware generator 负责"好看",下游一条三层物理管线负责"能装"。

上游由两个现成模型串联:Hunyuan3D 把一张图变成整体 mesh,X-Part 再把 mesh 切成语义零件。这一段的输出就是第一章里那些"红成一片"的零件,论文不指望它们自己变好。真正的工作在下游,三个串行子阶段:先是 PGE(Part Geometry Editing,零件几何编辑)修掉零件之间的穿透,再是 CGR(Connector Geometry Reasoning,连接器几何推理)给每个接触面设计和放置连接器,最后是 physics-based optimization,用物理仿真反馈把连接器调稳。SNAP3D

关键不在这三件事本身,而在它们的位置:物理被放在生成之后,而不是塞进生成过程。整条管线里没有一个端到端网络去学习"什么形状物理上立得住",物理层是显式的几何编辑加仿真迭代。这张全景图把整个分工摊开给你看:

SNAP3D 管线总览

图注:SNAP3D 管线总览。左半是 PGE → CGR → 物理优化的三段串联框图,每段配输入输出示意;右半上排是接触图与榫卯(peg-and-socket)爆炸视图,下排是同一物体在 IPC 仿真里的对比:基线生成的零件在重力下散架,SNAP3D 的装配体稳稳站住。这是几何物理两阶段管线图,不是端到端网络图。SNAP3D

这个"把物理移出生成器"的摆法,换来一个很实际的回报:物理层不绑定任何生成器(generator-agnostic),这是论文把输入定义为任意 part-level generator 输出的 mesh 所带来的设计性质。X-Part、OmniPart、PartCrafter、UniPart,乃至 PartGen 那种先做多视图分割、再逐零件补全重建的路线,只要输出是"一组按同一空间对齐的零件 mesh",这条物理层都能直接接上去用,不需要为每个生成器重写一遍。PartCrafterUniPartPartGen

这就像工厂里的出厂检验线:不管上游是哪条产线出的货,只要出的是能被拼起来的零件,就都过同一道装配校验关卡。关卡独立于产线,产线换代,关卡照用。论文实验里上游固定用 Hunyuan3D 加 X-Part,但架构上没有任何一处依赖某个特定生成器的内部结构,这是它敢把物理层做成"可插拔"的真正底气。

代价也随即而来:生成器交出来的烂摊子五花八门,物理层必须每一种都能收拾。最糟糕的一种是第一章那张图里的情况,零件在接触面穿成一团。下一章就从这里开始。

怎么把互相"打架"的零件,修成一条干净的接触面?

第一步 PGE 的目标是消除穿透。做法朴素到近乎粗暴:不加新东西,只删重叠。对每一对相交的零件,先算一个侵占度分数 s_ij,谁吃掉对方的体积更多、谁伸得更"深入",谁就当侵占者;然后把交集从侵占者身上直接布尔差掉。为了防止削着削着把零件削没了,每个零件设一个最大可丢失体积的上限,逼近上限时,就把侵占归属里差值最小的一对翻过来重判。最后,布尔差留下的浅角薄屑也被剔掉。SNAP3D

注意,这里没有任何"重新生成边界"的动作,几何是从原 mesh 里删出来的,所以零件的语义分割被完整保留。输出是一组不再互穿、但彼此也没有任何连接的干净零件。

无穿透听起来像魔法,其实背后有一条硬保证,后面所有环节都踩在它上面。仿真器用的是 IPC(Incremental Potential Contact,增量势接触)这套接触求解器,它的核心是一个 barrier potential(屏障势):接触对之间的距离越近,势能越大,距离趋近于零时势能发散。这就像两块同极磁铁,越靠近推力越大,物理上不可能真正叠进对方身体里。有了这条机制性的保证,"零件没有互穿"才能被当成可靠的事实来使用,而不是靠事后检查修补。IPC

但零件贴得近,不等于真的"接触上"了。接下来要建的接触图(contact graph)用两个条件同时判定一对零件之间算不算真接触:表面最小距离小于容差 δ,同时有效接触面积足够大,超过装配体尺寸平方的一定比例。两个条件缺一个,都算伪接触。想想两件家具只是边沿蹭到一起,看起来挨着了,实际一碰就分;它俩之间没有一块对得上的面,也就谈不上有接触面可以放连接件。只有一整块面对上,才配进接触图。

到这里,几何层面的烂摊子收拾完了:不穿了,也分得出谁和谁是真的贴在一起。但这也是几何能做到的极限。回到那把办公椅:把两个重叠的零件削开,它们还是两段各自悬空的木头,一松手照样往下掉。贴住不等于站住,缺的是把两件扣在一起的连接件。连接件从哪来?

修干净还不够:一截榫卯怎么长出来、怎么调稳?

SNAP3D 选的连接件是最朴素也最古老的答案:榫卯。一边出凸榫(peg),一边挖凹卯(socket),小零件出榫,大零件留卯。理由很实在:挖孔要费掉材料,大件余量足,经得起在它身上开洞。

一根榫卯由 6 个参数完全描述:在接触面上的位置 (u, v)、朝向 (α, β)、轴的半径 r 和插入长度 ℓ。参数化放在接触面的局部坐标系里做,而不是世界坐标系:位置在接触面切平面上滑动,锚点用最近点投影贴回曲面;朝向在指向 receiver(受卯方)内部的法向基础上做小幅旋转。这样不管参数怎么变,榫都贴着面、指向对方内部,不会悬空,也不会戳穿对面的零件。

怎么"扣住",是这个设计里最值得说的一处取舍。想让两个零件靠 press-fit 那种"越压越紧"的摩擦抓在一起是不行的——弹性预紧需要形变,刚体之间产生不了预紧;所以 SNAP3D 用几何互锁(snap-fit),把榫头做成比卯口宽的凸起。就像按笔帽,咔哒一下,帽沿的凸起越过凹槽边缘之后被几何挡住,进去就出不来。这类卡扣在塑料件里到处都是,它不是靠摩擦力撑着,是靠形状卡住,仿真也因此能真实地模拟它。

但参数定得好不好,几何上看不出来。每个候选参数都要丢进 IPC 仿真里完整 rollout 一次:把装配体放回原物位置,松手,看它在重力下怎么动。因为仿真 rollout 不可微,优化绕不开导数,用的是 CEM(Cross-Entropy Method,交叉熵方法):每一代采样 32 个候选,其中永远保留初始几何候选,保证结果不会比起点差;按目标函数排序,取 8 个精英,用一个全协方差的高斯分布重采样下一代。全协方差这个细节是有意的,它让参数之间的相关性被保留下来,榫的位置、朝向、尺寸是联动的,不能各自独立地瞎跳。SNAP3D

目标函数分两层。局部损失盯着这一对零件:$L_{\text{pair}} = \max(\Delta p_e / \tau_p, \Delta \phi_e / \tau_r)$,意思是这对零件的相对位移和相对转角各自不许超标,哪个超了按哪个算。全局损失盯整个装配体里所有自由零件的最坏情况,用它来拒绝"修好了 A、垮掉了 B"的设计。优化的执行方式也很有工程味道:仿真先定位出哪些连接失败了,只优化失败的那些,其它连接保持原样;每修好一个,重新仿真,暴露下一个,直到全部收敛。

"给零件之间设计连接器"这件事也不是 SNAP3D 凭空发明的,它的思想远祖是 2015 年的 AutoConnect,那篇工作已经证明了连接器可以按两个物体的几何自动生成并打印出来。SNAP3D 把这条思路从"两个独立物体之间"收窄到"同一个装配体的零件之间",再和仿真反馈耦合在一起。AutoConnect

到这里,整条管线齐了:修穿、定接触、长榫卯、仿真调稳。但一个新的问题浮上来:仿真里说"稳",就真的稳吗?稳这件事不能靠声称,得拿出证据。

凭什么相信它真能装回去?

SNAP3D 先交出的是一套评估协议,把"能装"变成可以判定的数字。做法很直白:把装配体在 IPC 仿真里放回初始位姿,松手释放,钉住接触地面的零件,然后量最大零件的平移和转角。判定分三档:稳定(stable)要求整个装配无穿透,且任意自由零件位移小于装配体包围盒尺寸的 6%、转角小于 10°;倒下(fallen)是位移超过 10% 或转角超过 25°;中间状态用最坏零件的平均位移(Shift)量化。

这套协议里藏着全篇最重要的一条防骗条款:无穿透这个前提不能省。想一想,一个宽容穿透的求解器,处理两个其实穿在一起的零件时,会用接触力把乱穿的部分硬夹住,两个零件被"夹"得分毫不动,读出来的恰恰是最稳定的结果。穿透不是被解决了,而是被掩盖了,乱穿被误判成稳。这就是为什么整套方法必须站在 IPC 这种无穿透求解器上,前几章埋的伏笔在这里兑现成一道硬门槛。

量化结果先看总表。所有数字都来自论文自报,代码与权重尚未发布,暂无第三方独立复现:

方法Stable(%)Falls(%)Shift ↓IVR(%)
X-Part0.064.073.54.86
OmniPart2.055.033.42.98
PartCrafter1.089.098.16.40
SNAP3D95.03.05.6<0.01

Stable 是松手后站稳的比例,Falls 是倒下的比例,Shift 是最坏零件的位移量,IVR(Interpenetration Volume Ratio,穿透体积占比)衡量还有多少体积在互穿。SNAP3D 把稳定率从最好的 2% 抬到 95%,位移比每个基线低 6 到 18 倍,穿透体积从百分之几压到 0.01% 以下。更难得的是几何几乎没有为代价:F1 从 X-Part 的 95.9 微降到 94.8,part-level 的 p-F1 从 81.3 到 80.6,跟最强的基线基本打平。性能是在保留原几何语义的前提下用接触编辑补出来的,不是把零件改成了别的形状。评估集是 HY3D-Bench 的 100 对带纹理 mesh 与图片,每件 2 到 18 个零件,覆盖家具、车辆、角色、工具和带关节的道具。SNAP3D

"95% 稳定"到底长什么样,以及三个阶段的功劳怎么分,看这张逐阶段演化图:

三阶段定性消融

图注:三阶段定性消融,同一物体从左到右依次是基线、PGE、CGR、完整管线(含物理优化)。前两列显示接触面从乱穿变成干净贴合,第三列可见新增的卡扣式榫卯(爆炸视图),右半两列是重力下的仿真表现:从一松手就散架,到最终稳稳站住。图中均为仿真渲染,不是打印件照片。SNAP3D

三阶段各自的贡献,数字上分得很清楚。同样用 X-Part 的零件输入,逐段叠加:

阶段穿透体积(%)稳定率(%)
原始基线4.860.0
+PGE0.0722.0
+CGR0.0086.0
+物理优化0.0095.0

这个表的读法很有意思:每一段都只解决自己那一个问题。PGE 几乎把穿透清零,稳定率却只到 22%,因为没有连接,零件们照样各自乱滚;CGR 补上榫卯互锁,跳到 86%;最后的物理优化再补 9 个点,处理的是纯几何完全看不出来的失衡。几何干净、有连接、仿真调稳,三件事缺一不可。再拆一层连接器参数空间:只用几何初值开局稳定率是 86%,全面搜索到 95%;分别砍掉朝向、尺寸、位置三个搜索维度,各掉到 92%、90%、90%。位置和尺寸最关键,想想也合理:位置不对会挖穿零件,尺寸过大会把连接处的壁撑薄,这两样是结构性的;朝向偏一点,仿真还能靠互锁兜住。

最后一关是真实世界。论文把 6 个物体用 PLA 在 Bambu Lab A1 mini 上 FDM 打印出来,全部靠 snap-fit 卡扣直接拼装,不用胶水、不用螺丝、不用任何外部紧固件,全部拼装成功。仿真里松手站得住,是仿真这一层的证据;打印机里真的拼回去了,是物理世界的证据。能装,是被测出来的,不是声称出来的。

一条可插拔的"物理层",走到哪、停在哪?

把 SNAP3D 放进"物理约束该加在哪一阶段"的地图里,它的位置一目了然。这条线有三条主流走法,代表工作恰好是同代的三个端点:

路线代表工作物理加在哪用什么度量
生成过程中加物理Atlas3DSDS 优化的 refine 阶段,直接改 mesh 顶点standability(站立稳定性)
采样时加物理PhysPart推理时把物理 loss 注入去噪采样循环motion success rate(动起来算成功)
生成后加物理SNAP3D生成后独立三层:修穿、定接触、连接器加仿真调稳装配后松开看是否垮,加 3D 打印实测

三个端点各自改了物理的"加法位置"。Atlas3D 在 SDS 的 refine 阶段把可微的站立损失直接作用到顶点上,一边画一边让物体站稳;

Atlas3D 仿真对比

图注:Atlas3D 的物理仿真对比:左栏由 Atlas3D 生成的模型在仿真中稳稳站立在地面上,右栏现有方法(Magic3D、MVDream 等)生成的同类模型在相同条件下倒下。这是"物理约束加在生成过程内"这条路线的效果展示,不是架构图。Atlas3D

PhysPart 则在去噪的每一步用物理 loss 的梯度推着采样走向可活动的形状:

PhysPart 管线

图注:PhysPart 的三段式管线:先用 Pose Proposal 预测缺失零件的包围盒,再做 SDF 潜空间的零件生成扩散,最后在去噪采样循环里用物理 loss 梯度引导结果。物理约束被注进采样过程内部,与 SNAP3D 在生成后做 refinement 的路线形成对照。PhysPart

度量也各说各话:Atlas3D 看单个物体会不会倒,PhysPart 看零件装上去还能不能动,SNAP3D 的"装配后松开"更严格,它同时要求零件之间的接触关系成立,而不只是整体不倒。Atlas3D

代价和边界同样摆在明面上。论文自陈了几条局限:仿真把零件和连接器都当刚体,没有材料形变,真实打印件在小间隙处可能因为 FDM 公差或塑料蠕变而垮掉;CEM 优化贵,间隙小时必须跑高保真接触,离实时还很远;只做 rigid assembly(刚性静态装配),关节、滑轨这类可动连接不在范围内,那是 PhysPart 的支线。上游生成器偶尔给出开口的壳而不是闭合实体,布尔差没有定义,大约 0.5% 的零件对仍会微穿,论文明确选择不重新生成 mesh,因为那会破坏语义分割这个前提。装配顺序规划也不是它的课题,像 Assemble Them All 那种"按什么次序把零件拼回去"的规划问题,与它"拼回去之后站不站得住"的验证正交,它只回答后者。Assemble Them All

所以 SNAP3D 的定位不是"又一个更聪明的 3D 生成器",而是把"物理"做成了一层人人可接的后处理,和一套人人可用的评估标准。对 3D 资产生成,它把可装配性变成一组能测量、能比较、能用打印机检验的数字;对机器人装配研究,它意味着下游拿到的输入从"看起来对的零件"升级成"经过物理验证的零件"。它诚实的地方在于知道自己的边界:刚性、静态、无形变。这是生成器之后物理层的第一站,不是最后一站。把"能不能装回去"从一个形容词,变成一组可以用仿真和打印机检验的数字,这件事本身就值得记住。

想深入可以读原文:SNAP3D: Physically Grounded 3D Parts for Assembly from a Single Image(arXiv:2609.13146)。

参考文献

SNAP3D:怎么让 AI 生成的 3D 零件真正拼起来?