用“折纸”求解三维网格:从可折的纸,到高保真模型
把“生成网格”换成“求解折法”:一张图拆成部件,每个部件用正方形纸折出——平面折痕、可展弯曲、镜面反射曲线折痕、压折与瓣壳,泊松充气给出三维目标,多张纸联合优化;再去掉折纸约束,用隐式场、Surface Nets 与误差有界 QEM 生成高保真网格,并接入浏览器内的单目深度。
Here-There

AI 三维生成交出来的几乎都是三角网格。折纸其实也在做同一件事:一张纸沿折痕折起、在顶点处被顶出来,纸面变成许多平面或曲面片,拼成一个立体。区别在于,折纸的每一片都来自同一张正方形,不能拉伸,也不能剪开。
这次实验想回答两个问题:
- **能不能把"生成网格"换成"求解折法"?**给一张图,程序决定用几张多大的纸、每张怎么折,最后得到一个由真实可折的纸面拼成的模型。
- 如果去掉折纸约束,同一套几何思路能不能直接生成高保真、面数最省的三维模型?
两个答案都做成了同一个网页里的两种模式。
- 在线演示:https://study.geobridge.cn/3d-rendering/origami-mesh/
- 全部计算在浏览器里完成(TypeScript)。三维视图用 WebGPU(vgpu)绘制,折纸说明书用 SVG;单目深度模型用 onnxruntime-web 在浏览器里运行。

一、纸是一种"带约束的网格"
把折好的纸看成网格,它比普通网格多一条硬约束:展开后必须是一张平的正方形。纸是可展曲面,处处高斯曲率为零。落到离散网格上就是:纸面内部任何一个顶点,周围各面的角加起来恰好是 2π。
而一个立体的顶点周围,各面的角和小于 2π,差值
δ = 2π − Σ αᵢ
叫做角亏,也就是离散的高斯曲率(对封闭多面体,所有角亏之和恒等于 4π)。纸不能拉伸,这部分纸只能折起来藏掉:在两个面之间夹一道三角褶,对折后压在内侧。Tachi 的 Origamizer 正是靠这一点证明了:任意多面体都能由一张不剪开的纸折出来。
这条约束贯穿全文:网格上每一处弯曲都要付出角亏,这个代价要么藏进褶里,要么交给可展曲面去消化。
二、整体流程
图片 ─► 分割主体 ─► 拆成部件 ─► 泊松充气得到三维目标 ─► 每个部件选一种可展构造
(可选:单目深度) │
WebGPU 模型 + 折纸说明书 ◄── 多张纸联合优化 ◄─────────┘
└────► 或:去掉折纸约束,生成高保真网格

三、从图片到部件
分割用的是简化版 GrabCut。图片边缘的颜色在 Lab 空间聚类作为背景色;物体色用远离背景的像素聚类得到。每个像素按"离背景色多远 − 离物体色多远"打分,平滑后取正值。用户框选时,程序会把框内区域按原始分辨率重新采样后再分割。
拆部件分两步:
- 按颜色拆:一张纸一种颜色,所以颜色天然就是部件边界。聚类时把亮度差的权重降低,避免阴影把一块纸劈成两块。
- 按粗细拆:做形态学开运算,半径取最大内切圆半径的约 0.42 倍。活下来的是身体、头这类"粗块",被削掉的是腿、尾巴、耳朵这类"细肢"。遇到细脖子时逐步加大半径,直到腐蚀结果裂成两块、且每块都明显比半径粗。
部件之间按接触边界长度建一棵最大生成树。细肢沿中心线测横向宽度剖面,按剖面形状分类:中间鼓的是叶或花瓣,末端扩开的是鳍,短而朝上的是耳朵,其余是管。
四、平面折痕模块
第一版只用平面折痕,四个模块都是"一张正方形、不剪纸、展开恰好铺满":褶锥、卷管、风琴叶、masu 方盒。

以褶锥为例。目标 n 棱锥各棱的方向是 dᵢ,相邻两棱的面角 αᵢ = arccos(dᵢ·dᵢ₊₁),角亏均分成 n 道褶,每道 g = δ/n。褶对折后要压在相邻面上,这要求 g/2 ≤ α,由此可以推出半锥角大约不能小于 22°:锥太尖,纸面就藏不下褶。

折叠过程用正向运动学计算:模块给出每个面最终的刚体位姿,相邻两面的相对变换必须恰好是绕它们共享折痕的一次旋转,由此反推每道折痕的转角和山谷方向,再按折叠程度插值。所有模块的闭合误差都在 10⁻⁸ cm 量级。
这一版的问题很直观:多面体看起来就是多面体,身体是尖顶棱锥,花瓣是直边纸片。
五、可展弯曲:让纸弯起来
纸不只能折,还能弯,只要弯成可展曲面。
**广义锥。**以纸上某点为顶点取极坐标 (r, θ),只要 g(θ) 是单位球面上的单位速度曲线,映射
(r, θ) ↦ r · g(θ)
就是严格的等距变换:∂/∂r 是单位向量,∂/∂θ 的长度恰好是 r,两者互相垂直。纸弯成什么形状,完全由 g 的测地曲率 k(θ) 决定:
- k = 0:纸保持平整;
- k > 0:纸向内收拢成杯形;
- k < 0:纸边向外卷;
- 切向在某处突变:纸上出现一道沿母线的直折痕(叶脉)。
把 k 乘以 0→1 的系数就得到折叠动画,而且每一帧都严格等距。平面模块的闭环折法做不到这一点。
玫瑰。花心是一张纸从一角卷成逐渐收紧的螺旋锥(k = cot ψ,ψ 逐渐变小)。每片花瓣是一个虚拟顶点在纸下方的锥面上的一段,锥顶都落在花头下方的轴线上,于是各层花瓣成为同轴的圆锥,内层紧、外层开,组成碗形。
**曲线折痕:镜面反射。**花瓣上缘外翻需要一道曲线折痕。这里用了一个严格又简单的构造:用平面 Π 切开花瓣曲面,把 Π 以外的部分沿 Π 镜像。反射是等距变换,并且固定 Π 上的点,所以折完仍是同一张纸。折痕就是曲面与 Π 的交线,在纸上是一条真正的曲线。瓣缘想朝向 w 时,Π 的法向取
n = (u − w) / |u − w| (u 为花瓣中线方向)
**压折:两次反射等于一次旋转。**尾巴、腿、仙人掌手臂都是卷成的锥管,要沿中心线弯折。两张镜面 Π₁、Π₂ 交于弯折内侧的一条直线 L:管子越过 Π₂ 的部分做两次反射 R₁∘R₂,合起来就是绕 L 的旋转;夹在两面之间的楔形纸只做一次反射,翻进管内藏起来。这和真实折纸里"内翻压折"的做法一致。
**瓣壳。**身体和头由 6–8 条长条围着主轴拼成,像西瓜瓣或纸灯笼。每条是沿一条经线弯曲的广义柱面 c(s) + u·e(c 为单位速度的平面曲线,e 垂直于 c 所在平面),同样严格等距。


六、三维目标:泊松充气
只拟合正面轮廓,求解器无从知道身体有多厚。所以先为每个部件求一个三维目标:在部件剪影内解泊松方程
Δu = −1,边界上 u = 0;厚度 h = √(2u)
对等宽的管,横截面上 u = (R² − r²)/2,于是 h 恰好给出圆截面;对团块,得到圆润的穹顶。沿部件主轴切片,就得到每一片的左右半宽和厚度。瓣壳的经线直接取自这些切片,压折锥管沿着中心线走,弯折处放置压折。
七、多张纸联合优化
各部件分别构造完,还要让它们彼此接得上。每个部件加一个小幅调整:平移、离开图像平面的倾斜和缩放。调整沿部件树向下传递,所以移动头部时耳朵会跟着走。能量函数为:
E = 6·(1 − 正面轮廓 IoU) + Σ 部件越出自身区域的比例 + 3·Σ 被遮挡比例(z 缓冲)
+ Σ 根部离父部件表面的距离(Huber;嵌入父部件体内记为 0)
+ 5·Σ 肢体穿进父部件体积的比例 + 小正则项
每张纸只采样一次成点集,每次评估只做矩阵运算,用 (1+1)-ES 和 1/5 成功率规则搜索约 360 步,浏览器里约 0.3–0.6 秒。如果优化后轮廓反而变差,就保留原来的构造结果。
优化后,猫的轮廓吻合度从 72% 升到 80%,小鸟从 67% 升到 80%,鱼从 69% 升到 77%,肢体根部间隙平均缩小一半。
八、去掉折纸约束:高保真网格模式
同一套"形状目标"如果不再要求能用纸折出来,可以直接走一条标准的三维重建流程,目标是形状最准、面数最少:
- **隐式场。**每个部件写成一个"厚片":F = max(到轮廓的有向距离, |z − z_c| − h),各部件用多项式平滑最小值融合,接合处平滑过渡。
- **等值面。**用 Surface Nets 提取,得到封闭网格,不需要查找表。
- **平滑。**Taubin λ|μ 平滑,去掉体素台阶,同时不让模型收缩。
- **简化。**QEM 边折叠(Garland–Heckbert):每个顶点累积其所在面平面的二次误差,代价最小的边先折叠,偏差到达上限就停。所以面数不是指定的,而是由形状决定:平坦处合并成大三角形,弯曲处保留细节。简化后实测 Hausdorff 距离,超出上限两倍就收紧阈值重做。
- **着色。**把照片颜色投影到每个面上,导出带顶点色的 OBJ。
| 示例(高 20 cm,允许偏差 0.6%) | 等值面 | 简化后 | 最大偏差 |
|---|---|---|---|
| 猫 | 30,072 面 | 3,726 面(12%) | 0.034 cm |
| 小鸟 | 37,096 面 | 4,432 面 | 0.038 cm |
| 仙人掌 | 24,540 面 | 2,980 面 | 0.035 cm |
| 蘑菇 | 35,588 面 | 2,394 面(7%) | 0.024 cm |

九、单目深度
剪影和充气只能给出"前后对称"的厚度,看不出谁在前、谁在后,也没有表面起伏。这一步接入 Depth Anything V2 Small(Apache-2.0),用 onnxruntime-web 在浏览器里推理。模型和运行时都放在本站服务器上,WebGPU 下用 4 bit 权重版本(19 MB,与半精度版本的相关系数为 0.998),推理约 3 秒。
模型输出的是只在仿射意义下成立的视差(尺度和平移都未知)。在物体范围内用 5%–95% 分位数把它归一化为 D,再规定深度范围 λ = 物体宽度的一半,然后:
- 折纸模式:部件的前后偏移 z_p = λ·(部件深度中位数 − 物体深度中位数)。
- 网格模式:厚片的中面跟随平滑后的深度弯曲;深度的高频部分作为正面起伏,在轮廓处逐渐减为零,并且不超过深度范围的 6%。
在真实照片上,深度让模型有了前后层次和面部起伏。但如果框选或分割时混进了背景,深度会把错误一起放大。
十、回到最初的问题
**折纸式求解能不能生成高保真的三维模型?**从几何上说可以。Origamizer 定理保证任意网格都可折;可展曲面加上折痕可以把任意光滑曲面逼近到任意精度,代价由高斯曲率决定:越弯的地方,褶或分片就越密。本文的瓣壳、压折和曲线折痕,就是这条路上几种具体、可手折的构造。
但生成三维模型真正难的地方不在折法,而在推断形状:背面长什么样、被挡住的部分是什么、表面有哪些细节。这部分要靠学习得到的形状先验,比如本文接入的单目深度,或者更强的图生 3D 模型。折纸约束本身不提供信息,它的价值在别处:
- 干净、紧凑、可编辑的表示:几十片参数化曲面,而不是几十万个杂乱的三角形。
- 天然可制造:纸艺、钣金、布料版型都是"可展片加折痕"。
- 强正则:等距约束会抑制噪声和破面。
去掉约束的网格模式说明,同一个形状目标加上误差有界的简化,就能用几千个三角形得到稳定、紧凑的模型。
下一步有三件事:把单张图的深度换成多视角或图生 3D 的完整三维目标;把分片可展拟合做成可微优化,直接以三维 Chamfer 距离为目标;为常见品类补充更多高保真模板。
相关文章
webgpu · 2026-11-06
Building a Music Box That Really Turns, from Scratch, with Claude + Blender
Blender-scripted modelling, WebGPU rendering and synthesized sound: a photoreal music box built with Claude Code, plus five bugs that passed every test.
15 分钟阅读 · Here-There

webgpu · 2026-11-06
用 Claude + Blender 从零做一个会“真转”的八音盒
用 Claude Code 协作,以 Blender 脚本建模、WebGPU 渲染、Web Audio 合成,做出一个能演奏、能看清原理的写实八音盒;附五个“测试全绿却依然出错”的坑与修复前后对比。
12 分钟阅读 · Here-There

评论 (0)
还没有评论,来说两句吧。