PartPacker 方法讲解

PartPacker 方法讲解

论文:Efficient Part-level 3D Object Generation via Dual Volume Packing
代码:NVlabs/PartPacker

1. 一句话理解

PartPacker 不直接为每个部件生成一个 3D latent,而是把所有部件分到两个体积中:

同一体积中的部件不能互相接触,因此解码后可以按连通组件自动拆开。

flowchart LR A[单张图片] --> B[DINOv2 图像特征] B --> C[Rectified Flow / DiT] C --> D[两个 3D latent] D --> E1[VAE 解码 Volume 0] D --> E2[VAE 解码 Volume 1] E1 --> F1[连通组件拆分] E2 --> F2[连通组件拆分] F1 --> G[完整部件集合] F2 --> G

2. 它要解决什么问题?

普通 image-to-3D 方法通常输出一个融合网格:

椅子 = 椅面 + 椅腿 + 靠背

这些部分会融合在同一个 mesh 中,难以单独编辑。直接为每个部件分配一个体积又有两个问题:

  • 部件数量可变,网络输出长度难以固定;
  • 部件越多,生成计算量越大。

PartPacker 的目标是:

固定生成两个体积
        ↓
每个体积中可以包含任意数量的独立部件
        ↓
解码后按连通组件拆出部件

3. 双体积打包

3.1 把部件关系变成图

构造部件接触图 \(G=(V,E)\):

  • 顶点 \(V\):3D 部件;
  • 边 \(E\):两个部件在空间中接触;
  • 相邻顶点不能放入同一个体积。

这等价于图着色问题:

graph LR Seat[椅面] --- Back[靠背] Seat --- Leg1[椅腿 1] Seat --- Leg2[椅腿 2] Seat --- Leg3[椅腿 3] Seat --- Leg4[椅腿 4]

一种合法分配可以是:

Volume 0:椅面
Volume 1:靠背、四条椅腿

只要同一体积中的部件互不接触,解码后的网格就会有多个连通组件。

3.2 非二分图的处理

如果三个部件两两接触,会形成奇环:

graph LR A[部件 A] --- B[部件 B] B --- C[部件 C] C --- A

这种图不能只用两个颜色表示。PartPacker 使用启发式的奇环收缩:

flowchart TD A[检测接触图中的奇环] --> B[计算每条接触边的穿透深度] B --> C[选择穿透最深的边] C --> D[合并这两个部件] D --> E{是否仍有奇环?} E -- 是 --> A E -- 否 --> F[二着色并分到两个体积]

穿透深度较大的两个部件本来就更容易被视为一个整体,因此优先合并它们。

4. 数据准备

flowchart TD A[GLB 网格] --> B[读取场景图中的部件] B --> C{是否有可靠部件信息?} C -- 否 --> D[使用连通组件作为部件] C -- 是 --> E[使用场景图部件] D --> F[合并伪分离组件] E --> F F --> G[修补开放边界] G --> H[建立部件接触图] H --> I[奇环收缩与双体积打包] I --> J[转换为 SDF 和表面采样] J --> K[训练 VAE 与 Flow]

每个体积会被转换成 watertight mesh,并生成:

  • 均匀表面点;
  • 显著边缘点;
  • 点与 SDF 值,用于监督几何重建。

两个体积的占用比例过于不平衡时会被过滤,因为一个几乎为空的体积不利于训练。

5. 网络结构

flowchart LR I[输入图像] --> D[DINOv2] D --> C[图像条件特征] N0[随机噪声 latent 0] --> T[DiT / Rectified Flow] N1[随机噪声 latent 1] --> T C --> T T --> L0[latent 0] T --> L1[latent 1] L0 --> V0[共享 VAE 解码器] L1 --> V1[共享 VAE 解码器] V0 --> S0[Volume 0] V1 --> S1[Volume 1]

关键设计:

  1. 两个 latent 联合去噪:两个体积可以通过 Transformer 交换信息,保持整体结构一致。
  2. 第二体积使用 part embedding:帮助模型区分 Volume 0 和 Volume 1,避免生成两个相同体积。
  3. VAE 采用显著边缘采样:加强对尖锐边缘和细节的重建能力。
  4. Rectified Flow:从随机噪声逐步生成 3D latent,不同随机种子可以得到不同结果。

代码中的默认单体积 latent 大小约为 \(4096 \times 64\),双体积拼接后大致为 \(8192 \times 64\)。

6. 训练流程

flowchart TD A[融合网格数据] --> B[预训练普通 VAE] B --> C[预训练普通 Flow] D[双体积部件数据] --> E[微调 Part-level VAE] E --> F[微调双 latent Flow] C --> F F --> G[最终 PartPacker]

微调 VAE 是必要的,因为部件网格可能很小、偏离物体中心,直接使用融合网格 VAE 容易出现伪影。

7. 推理和文件输出

sequenceDiagram participant U as 输入图片 participant F as Flow 模型 participant V as VAE participant M as 网格处理 U->>F: 提取图像条件 F->>F: 同时生成两个 latent F->>V: 解码 latent 0 和 latent 1 V->>M: 得到两个体积网格 M->>M: 按连通组件拆分 M-->>U: 输出完整物体和独立部件

典型输出:

object_0.glb          # 所有部件组合后的物体
object_0_vol0.glb     # Volume 0
object_0_vol1.glb     # Volume 1
object_0_part0.glb    # 独立部件 0
object_0_part1.glb    # 独立部件 1
object_0_part2.glb    # 独立部件 2

因此,每个 *_partN.glb 都是一个独立的 mesh 文件;但模型内部首先生成的是两个包含多个部件的体积。

8. 优点与局限

优点 局限
不需要额外的 2D 分割模型 部件粒度依赖原始网格标注
一次生成所有部件 不同随机种子可能产生不同划分
输出部件数量可以变化 三个以上部件互相接触时,双体积表达能力不足
推理时间不随部件数量线性增加 奇环收缩可能合并两个语义不同的部件
输出的是完整 3D 部件,而不是可见表面片段 复杂内部结构可能生成错误或缺失

9. 最核心的理解

PartPacker 的关键不是“预测一个部件列表”,而是:

部件接触图
    ↓
二分成两个互不接触的部件集合
    ↓
联合生成两个 SDF 体积
    ↓
按连通组件恢复任意数量的部件

也可以概括为:

用固定长度的双体积表示,解决可变数量的部件生成问题。

posted @ 2026-10-14 13:42  S-X-Q  阅读(11)  评论(0)    收藏  举报