给一张图重建 3D,常规做法:吐一个几百万面的网格;

有个开源项目偏不——它把模型写成程序。同时它真正的狠活,是“逼 AI 别偷懒”。


作者 | 听风

编辑/排版 | MM77

翠鸟AI技术漫研 — 拓新AI边界、探索技术增量


「给一张图,帮我建个 3D 模型」——这需求现在满地都是。

主流做法你大概能猜到:喂给模型,它吐出一个网格文件,几十万上百万个三角面,本质是把照片当尺子量,量出一堆点云再连成面。

能用,但出来的是个死疙瘩:想让它动起来得另外绑骨骼,想改个零件几乎无从下手,文件还大得吓人。



最近翻到一个叫 img2threejs 的开源项目,它偏不走这条路。

它不给你文件,它把这个模型「写」成一段代码。

这个反直觉的选择,还有它为此配的一整套质检机制,值得盘一盘——尤其是后半段,藏着一个 AI 时代很多产品假装看不见的问题。



01. 何为反直觉的选择:像木匠看图纸搭东西

  1. 常规重建像考古:对着照片一点点抠出物体表面,堆成密密麻麻的三角网。
  2. 而 img2threejs 干的事更像木匠看图纸搭东西——它读懂这张图里是把手枪,然后用代码把它搭出来:
  3. 一个圆柱当枪管,一个盒子倒角成弹匣,几行着色器程序画出金属那种冷冷的反光;交给你的是一段能在浏览器里直接跑的 Three.js 程序,不是一个 .obj 文件。



这带来几个网格文件给不了的好处:

// 常规网格:一整块死数据

gun.obj → 2,400,000 个三角面,一个焊死的整体

// img2threejs:一段有结构的程序

createGlockModel()

├─ barrel (圆柱,可单独旋转/拆卸)

├─ slide (可后座,天生带 pivot 轴)

├─ magazine (可插拔 socket)

└─ trigger (可扣动)

因为是「搭」出来的,每个零件天生是独立的、有名字的、可以动的。

枪管就是枪管,弹匣就是弹匣,你想让弹匣掉出来,代码里它本来就是个能插拔的部件,不用你反过来去一个死网格上硬猜哪几万个三角面属于弹匣。

它还顺手把「哪里该转、哪里能挂东西、哪里会碰撞」这些运行时信息一并生成好,交给你的是个能直接上手的活物,不是一具死标本。

代价当然有:这种手法擅长的是硬邦邦的物件——枪、刀、自行车、耳机、机械。

越是有机、越是要照片级真实的人脸,越难纯靠代码搭出来(后面会讲它对这件事有多诚实)。

但对绝大多数「我要个能动的道具」的场景,一段几十 KB、能 diff、能改、能进 git 的代码,比一个几十兆的死网格值钱太多。



02. 真正的狠活,在「怎么防止 AI 糊弄你」

如果只是「用代码搭模型」,这还只是个巧思。让我真正坐直的是它的另一半:一整套逼着 AI 别偷懒、别自欺的质检门。

要知道,让大模型看着图搭 3D,它有一万种方式糊弄过关;而这个项目像个不好糊弄的老师傅,专门堵这些偷懒的路。挑三个最好懂的说。

  1. 狠活一:一张假贴图,栽在「你到底有没有厚度」上

项目文档里记着一次真实的翻车。

它重建一把 Glock 手枪,各项指标都漂亮:轮廓吻合度 98.6%,颜色几乎全对,转着圈看也都对得上。可用户一眼就看穿了——「这就是张贴图。」

怎么回事?AI 偷了个懒:它把一张手枪的照片,贴在了一块平板上。

正面看天衣无缝,因为所有验收指标都是从正面算的——而平板最擅长的就是骗正面。

轮廓吻合度那 98.6% 不但没帮上忙,反而在帮凶:它就是从顶视图算的,一块平板压出来的轮廓当然完美。



项目的破解办法特别朴素,朴素到你会心一笑:数一数这个零件在纵深方向上,有几个不同的厚度值。

// 沿纵深方向,这个零件出现过几种不同的「厚度」?

真·枪管 → 15 种厚度值 这是个立体

真·准星 → 13 种厚度值 这也是个立体

假·弹匣 → 10 种厚度值 几乎是张纸

假·扳机 → 10 种厚度值 还是张纸

一个真的枪管,你顺着它的纵深切一刀,会切出十几种不同的厚薄;

而一块平板,从头到尾就那么一个厚度,翻来覆去也就凑出十种。

这个检查不看颜色、不看轮廓、不看任何能被贴图骗到的东西,它只问一句最笨的话:你,到底有没有体积?一张再逼真的贴图,也答不上这道题。

一个指标越是好看得让人放心,越值得回头问一句:

它到底测的是真本事,还是恰好能被糊弄的那个角度?

真正防得住自欺的,是找一个贴图再漂亮也伪造不了的维度去问——比如「你有没有体积」。

  1. 狠活二:体力活交给死脚本,AI 只干判断活

第二个聪明处,关乎钱——准确说,关乎 token。

市面上大多数「AI 建模」的流程有个通病:

每走一步都让大模型重看整张图、重新逐像素打分、重新校验一遍格式、把做过的活再确认一遍。

大模型是按字数收费的,这么干,钱像流水一样淌出去,还慢。

img2threejs 的分工干净得多:凡是机械的、有标准答案的活,全部交给零依赖的 Python 脚本去干;

大模型只留下来干一件事——看一眼「参考图 vs 我搭出来的样子」,判断像不像。



  1. 交给死脚本(不花一分钱):

校验格式对不对 · 算两个颜色差多少 · 数厚度值

把参考图和渲染图拼成对比图 · 管流程走到第几步

  1. 只留给大模型(花钱,但只花在刀刃上):

看着这张对比图 —— 像,还是不像?过,还是打回?

一句话概括它的哲学:脚本负责卡关,模型只负责判断。

算两个颜色差多少(它用的是一套叫 CIEDE2000 的色差公式,越接近人眼感受),这种有唯一正确答案的事,凭什么要花大模型的钱去「感觉」一下?

交给脚本,一分钱不花,还比模型算得准。把判断力这种真正稀缺的东西,省着用在唯一需要它的地方——「这俩到底像不像」。

顺带一提,这些脚本刻意做到零依赖,纯 Python 标准库,连读写图片都自己用底层字节码搞定,不装任何第三方库。

为什么?

因为每多一个依赖,就多一份「哪天它报错了、得让 AI 花上下文去 debug」的负担。省 token 这件事,被它抠到了每一个环节。



  1. 狠活三:逼它承认「这块是我猜的」

第三个,是我最欣赏的一条,因为它对治的是 AI 最坏的一个毛病:不懂装懂,还装得理直气壮。

你给它一张人脸的正面照,让它重建。背面呢?侧面呢?照片里根本没有。

一个偷懒的 AI 会怎么做?编一个,然后当作自己「看到」的呈现给你,脸不红心不跳。



这个项目明令禁止这种事。规则写得死死的:凡是照片里没有的区域,绝不许假装看到过。

它会做三件事——

  1. 首先主动开口找你要:「能再给我一张侧面/背面照吗」;
  2. 实在没有,就从对称的另一半镜像过来,但会老实标注「这是我镜像推断的」;
  3. 再不行才用最近处的颜色续上,并标成最低置信度。每一块推断出来的区域,都挂着一个诚实的置信分。

还有一条我觉得该裱起来的规定:它永远不许输出「100% 还原」这句话。

因为单靠一张图,物理上就不可能保证百分百——那就别给用户一个虚假的安心,改成一区一区地报「这块我有几成把握」。



一个系统成不成熟,光看它多能干还不够,得看它清不清楚自己哪儿不能干——而且肯大声讲出来,

别拿一个漂亮的输出把心里的没底盖过去。

03. 一把尺子:它想拿高分,还是想给你可信的结果

盘到这儿,这个项目给了我一把尺子,可以用来掂量任何一个 AI 系统——不只是建模的。

回头看它那三招,指向的其实是同一件事。

  1. 数厚度值,是不让「拿高分」等于「真的对」;
  2. 死脚本管卡关,是把判断力省给真正的判断;
  3. 逼它承认猜测,是不让一个漂亮的输出盖住底下的心虚。

三招都在对抗同一个诱惑——AI 太容易学会怎么把指标刷好看,而把事做对这件更难的,就悄悄放一边了。

「指标好看」和「事做对了」经常是两回事,有时甚至是反的。那把假贴图就是活标本:指标满分,结果错的。



你面前这个 AI 系统,到底是在冲着高分使劲,还是在替你把事做对?

这俩看着像,其实两回事。

一个只想拿高分的系统,会挑最容易骗过验收的那个角度发力,把没把握的地方悄悄抹平,在你看不见的犄角旮旯偷工——反正指标漂亮就行。

而真想给你可信结果的,做法反过来:

它会主动去找那个自己最难糊弄过去的维度来考自己,没把握的地方明明白白标出来,实在做不到的,宁可当面告诉你「这个我搞不定」,也不糊一个假的塞给你交差。



三维重建只是个由头。

等 AI 开始替我们判断越来越多看不见对错的事情,这把尺子只会越来越值钱:

能干,是本事;知道自己哪儿不能干、还老实说出来,是更稀缺的本事。

一个开源建模工具都把这条想明白了、并且用一行行代码守住了,那些把「全都能做、准确率 99%」打包一口价卖给你的,心里到底有没有这根弦,你自己掂量。