目录

Apparent Layer Operations for the Manipulation of Deformable Objects


作者Takeo Igarashi, Jun Mitani
机构The University of Tokyo / JST ERATO; University of Tsukuba / JST ERATO
发表ACM SIGGRAPH 2010 (ACM Transactions on Graphics 29(4))
链接https://www-ui.is.s.u-tokyo.ac.jp/~takeo/papers/layer.pdf

相当于把 Photoshop 的「上移一层 / 下移一层」(准确说是 McCann & Pollard 2009 的 local layering)搬到俯视的 3D 布料和绳子上:点一下时,把场景投影成一张平面区域图,每块区域里是一叠有序的布片;然后暴力枚举所有不穿模的叠放组合(一个小型约束满足问题),挑「逆序对最少」的那个,再用最小二乘把离散顺序还原成连续 z 值,最后交给物理模拟收尾。拖拽时则按鼠标下方的叠放顺序给被拖顶点的 z 夹上下界。

Figure 1
图 1:两种操作。左:layer swap——每点一次领带的交叉处,该处的上下关系就翻转一次。右:layer-aware drag——拖动蓝色方布,按住 shift 时从粉色带子下面穿过,松开 shift 时从上面盖过。全程只有单一俯视视角,不切换相机。
2种交互:点击交换 / 拖拽穿越
294最难例子(领带)的合法组合数
1.45 s该例穷举搜索耗时(2010 年 1.2 GHz 笔记本)
10名用户的非正式 user study

术语速查

论文里的抽象词,在这篇论文的具体任务中各自指什么:

术语在本文中具体是什么
apparent layer从正上方往下看时,屏幕某块区域里的一片连通布料(或一段绳子)。不是持久数据结构——每次操作时临时算出来,用完即扔。「apparent」= 看上去的层,而不是模型里存的层。
planar map把所有布料边界、折线(或绳子轮廓)投影到屏幕上,切出来的一张 2D 多边形划分图。
regionplanar map 中的一个面。区域内部各处「叠了几层、谁在谁上面」都一样(图 7 中的数字就是层数)。
layer布料:某 region 里一个连通的 mesh 片段,附带它包含的顶点。绳子:与该 region 相交的一串球体(一个球可同时属于多个 layer)。
list graph节点 = 至少有 2 层的 region,节点里存一个从上到下的有序 layer 列表;边 = 两个 region 相邻且有 layer 在原始布料上是连着的。
type I violation相邻 region 之间的顺序矛盾:左边区域 A 在 B 上,右边区域 A 的延续却在 B 的延续下面 ⇒ 两片布在交界处互相穿过。
type II violation同一 region 内,共享一条折线的两层在顺序里不相邻,即有别的布插进了折缝 ⇒ 折缝处穿模。只在布料系统出现,是本文新加的约束。
swap(打分单位)一对 layer 在新顺序中的相对上下关系与原来相反,即一个逆序对(Kendall tau 距离)。n 层的区域最多 n(n−1)/2 个。
fraction拖拽算法用的最小单元:布料的一个三角面,绳子的一个球。被拖的 fraction = 与被拖顶点相连的那几个三角面。
boundary drag / intact drag拖边界顶点:其余部分靠物理模拟跟随(用来旋转、弯折、对折)。拖内部顶点:整块布一起平移。
shape matchingMüller et al. 2005 的无网格变形模拟:每帧把粒子拉向「最佳刚体变换后的原形状」。这里只用来保持布 / 绳的完整、推开轻微碰撞,不追求物理真实。

研究动机

核心方法

场景表示很普通:布料是单层三角网格,绳子是一串球。用 shape matching 做简单物理和碰撞,并假设操作前场景没有穿模。两种操作都遵循「临时算出表观层 → 在层上做决策 → 改 z → 物理收尾」。

1. Layer swap —— 点一下,交换鼠标下最上面两层

用户点击某处,系统让最上面那层移到它下面那一层的下方。只换这两层常常不可能:可能在折缝处穿模(图 2g→h,系统自动多换一层),或者必须把交换传播到周围区域才不会互穿(图 2c→d/e/f)。合法结果不止一种时,返回改动最小的那个(图 2c 返回 d)。想要别的结果,就在结果上别的位置再点一下——作者试过用缩略图让用户挑候选,发现小图看不懂、逐个看又烦,不如多点几下快。

Figure 2
图 2:基本 layer swap。a→b:最简单的两圆交换(小框是侧视图)。c→d/e/f:把蓝圆移到红圆下面后,三种合法结果都可能,系统按最小改动返回 d。g→h:蓝布下面的黄布有折叠,只换顶两层会让蓝布插进黄布的折缝,系统自动额外多换一层。

更极端的情况:对折两次的餐巾有两种合法结果,返回 swap 最少的那个,再点中心就得到另一个;卷成螺旋的布只有一种合法结果——整卷所有局部层顺序全部反转。

Figure 3
图 3:复杂的 layer swap。上:对折两次的餐巾,两种合法构型。下:螺旋,唯一合法结果是全部反转——一次点击改变了离点击处很远的层。
Figure 4
图 4:绳结上的 layer swap。每点一个交叉,该交叉的上下关系翻转,三次点击把一个结变成另一个结。

为什么只做「交换顶两层」?① 单击最快;② 在不同位置连续点击就能到达多种构型;③ 深层看不见,本来就很少要动(动深层需要先隐藏上层等额外操作,不在本文范围)。

2. Layer-aware drag —— 拖动时自动选择从上面过还是从下面过

拖动时 z 自动调整:原来在谁上面 / 下面,继续保持,避免拖着拖着突然穿过去;新碰到的物体,默认从上面盖过(drag-over),按住 shift 从下面钻过(drag-under)。两种拖法:boundary drag(拖边界顶点,只调被拖顶点附近的深度,其余靠模拟跟随)和 intact drag(整体平移,只调「前进前沿」——运动方向朝外的边界边——附近的深度)。

Figure 5
图 5:上:把绿布 A 拖到 B 上面(drag-over),再拖到 C 下面(drag-under),过程中 A 与 D、E 原有的上下关系保持不变。下:用连续三次拖拽(上、下、上)演示打结过程。

3. 最关键的一句话

把「改叠放顺序」变成一个离散约束满足问题——每块区域选一个排列,相邻区域不矛盾、折缝里不夹东西——取改动最少的解,再用最小二乘把排列还原成连续 z。

Layer swap 算法

flowchart LR
  A["Click"] --> B["Planar map"]
  B --> C["List graph"]
  C --> D["Per-region perms"]
  D -->|"drop type II"| E["BFS combine"]
  E -->|"drop type I"| F["Score"]
  F -->|"min weighted swaps"| G["Least squares z"]
  G --> H["Shape matching"]
          
drag to pan · scroll to zoom
Layer swap 流水线:点击 → 投影出平面区域图 → 建 list graph → 每个区域枚举排列(去掉折缝穿模的)→ 从点击区域广度优先组合(去掉相邻矛盾的)→ 按面积加权逆序对打分取最小 → 最小二乘解 z → 物理模拟收尾。

0. 为什么 local layering 的贪心传播不够

原版 local layering 是单遍传播 flip-up / flip-down:先在点击处翻转,再一路把冲突推给邻居。遇到折叠和自遮挡就失效:

Figure 6
图 6(侧视):左,折叠——在 p 处把 A 移到 B 下面,传播时发现 C 在 B 上方,于是把 A 也移到 C 下面;但 C 和 D 是同一张布在 q 处折过来的,A 插进折缝就穿模,必须回溯改成移到 D 下面。右,螺旋——A 移到 B 下面后,传播会一路走到把 B 移到 C 下面,等于把刚才的交换抵消。连回溯都救不了,只能全局搜索。

1. 构建 planar map 与 list graph

  1. 切折线(仅布料):在轮廓边(折线)处把网格切开,折线两侧成为两个独立片段。
  2. 投影:把所有折线和边界边(绳子则是轮廓)投到屏幕,得到 planar map;每个面是一个 region,region 内每个连通片段是一个 layer,按深度排序。
  3. 建图:region 为节点,有布料连通的相邻 region 之间连边。删掉只有 1 层的 region(没得交换),再删掉与点击区域不连通的部分。

与 local layering 的关键区别:列表里的条目是物体片段而不是物体 ID,所以同一块布折过来压住自己时,会在同一 region 里出现两次,自遮挡就自然能表示了。

Figure 7
图 7:planar map 示例。a/b:三块布及其区域划分;c/d:绳结及其区域划分。数字是该区域的层数。
Figure 8
图 8:list graph。黑点是有 ≥2 层的区域,每个区域挂一个从上到下的颜色列表(哪块布在上),实线是区域间的相邻连通关系。

2. 合法性:两种违规

Figure 9
图 9:左侧两个列表是 type I 违规——相邻区域里两块布的上下关系对调了(交界处必然互穿)。右侧列表是 type II 违规——浅蓝布折叠后的上下两半中间夹进了黄布(虚线弧表示两半在折缝处相连),折缝处穿模。

3. 穷举搜索

  1. 区域内:对每个 region 枚举全部 \(N_i!\) 个排列,删去含 type II 违规的;点击所在 region 还要删去不满足用户请求(原顶层必须到原第二层之下)的。每个区域的候选按 swap 数排序(0 = 原顺序)。
  2. 区域间:从点击的 region 出发广度优先访问。维护一个「暂定解集」;每访问一个新 region,把它的每个候选排列与解集里每个组合配对,只保留没有 type I 违规的组合。
  3. 打分:每个完整组合的分数 = Σ(区域 swap 数 × 区域面积);取最小者,其余丢弃。
Figure 10
图 10:点击左下区域后,每个区域的合法排列及其 swap 数。打叉的是被删掉的:点击区域里的原顺序不满足请求;右下的三层区域里有两个排列把黄布夹进了折缝(type II)。
Figure 11
图 11:左上是原始状态(0 swaps),其余 6 个是全部合法组合,swap 数 4–10。系统返回 4 swaps 那个;用户若要别的,再点别处即可。

作者明确知道这是组合爆炸问题(找全局一致的叠放顺序与平折折纸可折性同类,NP-complete,Bern & Hayes 1996),但目标场景一般只有 1–2 层、最多 5–6 层,穷举够快,且比 beam search 更不容易漏掉好解。打分规则也只是初步方案:作者提到可以对谷折 / 山折方向的改变额外罚分(视觉上很显眼),或者按离点击点的距离加权。

4. 从离散顺序还原 3D 几何

每个 layer 一个未知深度 \(z_l\)。解一个最小二乘:同一 region 内上下相邻两层的深度差等于物体厚度 \(t\);不同 region 之间相连的层深度差为 0;再固定一个中心点,去掉整体平移的自由度:

\[ \min_{z}\;\sum_{\text{region } r}\;\sum_{(l\,\text{above}\,m)\in r}\big(z_l - z_m - t\big)^2 \;+\;\sum_{(l,m)\ \text{connected across regions}}\big(z_l - z_m\big)^2 \;+\;\big(z_{c} - z_{c}^{0}\big)^2 \]

然后把层深度写回顶点:布料顶点取所属层的深度,折线上的顶点取两侧复制顶点的平均;绳子的球取所属各层深度的平均。最后跑 shape matching 把形状抚平。

Figure 12
图 12:点击 → 最小二乘给出分层但棱角分明的结果(中)→ 物理模拟得到平滑结果(右)。下排是侧视图。

Layer-aware drag 算法

只处理被拖的 fraction(三角面或球),每一帧给它算一个新 z。intact drag 时对前进前沿上的每个顶点各跑一遍同样的算法。

Figure 13
图 13:左,被拖的粉色片段从当前位置移向目标位置(虚线圆)。右,(a) 当前位置的层叠,(b) 目标位置的层叠;L 是当前位置下方的片段,L′ 是目标位置上与 L 相同或相连的片段,由此得到上下界,drag-over / drag-under 再修改其中一个界。
  1. 当前位置的层叠:找出屏幕投影与被拖片段相交的所有片段,按深度排序。比它低的组成列表 L。
  2. 目标位置的层叠:同样排序。目标处那些「属于 L 或与 L 中某片段在网格上相连」的片段组成 L′,L′ 的最高者是下界(原来压着的东西继续压着)。同理得到上界(原来在上面的继续在上面)。
  3. 新遇到的物体:drag-over 模式下,把「上界之下最高的片段」设为新下界(盖过所有新碰到的);drag-under 模式下,把「下界之上最低的片段」设为新上界(钻到所有新碰到的下面)。
  4. 夹紧:默认 z 取上一位置的深度;若落在 [下界 + 厚度, 上界 − 厚度] 之外就夹回来。若两界间距小于两倍厚度,取中点,让后续模拟把它们推开。

直观理解:这是 Sketch 系统「新物体放在下方物体表面上」规则的推广——不只看正下方是什么,还看它和刚才压着的是不是同一块布的延续,所以拖过一块本来就垫在下面的布时,不会突然钻到它下面去。

主要实验结果

性能(Table 1)

spiralnapkinscarfribbontie
顶点数21318490165122
区域数412253345
层数(各区域合计)7244577107
合法组合数121240294
planar map + list graph (ms)719453218422407
穷举搜索 (ms)1.33410761453
beam search (ms)1.3320.54.55.3
各阶段耗时(对数轴)。穷举随区域 / 层数增加急剧上升,领带例子比 beam search 慢约 270 倍;但在前四个例子里,建 planar map 的几何预处理(约 0.2–0.7 s)才是大头。

复杂度:穷举部分是 \(O\big(\prod_{i\in\text{regions}} N_i!\big)\),只取决于区域数和每区域层数,跟网格分辨率无关;网格面数只影响建 planar map,是线性的。

Figure 15
图 15:Table 1 中的 scarf、ribbon、tie 三个 layer swap 例子,每个都是一次点击。

User study

Figure 16
图 16:user study 的三个任务(start → goal)。
Task 1Task 2Task 3
耗时 (s)121.3 ± 41.347.5 ± 22.039.2 ± 12.5
点击次数24.2 ± 8.710.0 ± 7.29.4 ± 4.6
撤销次数0.0 ± 0.00.4 ± 1.30.0 ± 0.0

结论:多数人很快上手,几乎不撤销;少数人觉得某些交换结果出乎意料,但试几次也都完成了。注意 Task 2/3 平均要点约 10 次,说明「一次点出想要的结果」并不常见——用户是靠在不同位置多点几下来「搜索」的。

Figure 14
图 14:带贴图的衣物摆放场景(裤子、格子裙、衬衫),代表目标复杂度:大多 1–2 层,最多 5–6 层。
Figure 17
图 17:用绳结工具做的结。类似结果前人(如 Fabianowski & Dingliana 2008)也能画出来;本文的贡献在于能对已有的结做局部点击 / 拖拽修改,快速试不同构型。

局限与展望