打开网易新闻 查看精彩图片

2023年前后,如果你让最强的大语言模型直接写代码生成一个三维物体,比如一辆装甲越野车,它确实能写出来。但打开渲染结果你会发现,那辆车的轮子是圆柱体拼出来的方块感造型,车身是几个大盒子的堆叠,细节全无。这不是模型笨,而是任务本身太难了:一次性把几十个零件的形状、尺寸、位置全部想清楚再写出来,任何人类工程师坐下来闭着眼睛画图纸都做不到,何况是没受过三维训练的语言模型。

这就是南京大学团队做Procedura这项研究要解决的问题。

生成一个三维模型,到底卡在哪

先说说现在两条主流的三维生成技术路线,都各自有硬伤。

一条路线是原生三维生成器,通过扩散模型直接从图片或文字预测出一个隐式场或者体素网格,再解码成网格。这类方法这几年进步飞快,能从一张图片里恢复出让人惊叹的几何细节。但它们生来是为了拟合表面形状,训练数据来自扫描件和艺术家手工建模,学到的是柔和、有机的曲面感。一个机械零件应该有的锐利棱角、精确平面,在这类方法里全被磨圆了。更麻烦的是,生成出来的是一整块不分你我的三角面片,哪块属于哪个零件,模型自己也说不清楚,想要拆分只能靠后续再套一个分割模型,而分割模型切割的依据是表面几何形状而非零件的实际功能,所以往往连机器人手掌的哪根手指都分不出来。

另一条路线是自回归网格生成,像写句子一样一个顶点一个面片地吐出网格。但这类方法受限于生成序列的长度预算,能塞进去的细节天然有上限。

两条路线还共享一个更根本的缺陷:编辑困难。网格上没有任何可调的参数,想改设计只能直接在曲面上动刀子,这对普通用户几乎不可能。

**三维形状写成代码,本应该是更聪明的路子**,因为程序天然是参数化的,天然带着结构。这几年GPT、Gemini这些大语言模型写代码的能力突飞猛进,也确实有人拿它们去写Blender脚本、写Three.js场景。可现实是,让一个语言模型一次性把整个物体的代码写完,出来的东西都是玩具级别的,低多边形、没有细节。

这背后的原因值得琢磨。一次单独的生成调用,必须在没有任何反馈的情况下,同时敲定物体的每一个零件、每一个尺寸、每一处摆放位置。

打个比方,这就像蒙着眼睛拼一整台发动机,你不能中途摸一下拼到哪了,只能凭记忆和空间想象一口气把所有零件焊接到位。如果发动机只有三五个零件,凭记忆力或许还撑得住;但一旦零件数量涨到二三十个,人类工程师自己都会记混哪个螺栓该拧在哪个位置,语言模型自然也会。这就是为什么此前所有单次生成的三维代码系统,写出来的机械总是零件数量对不上、位置对不上,本该拼接的部件飘在半空中成了孤立的"浮子"。

Procedura的解法:把大问题拆成一连串小问题

Procedura团队的核心思路是把物体表示成一种叫做程序化装配体的东西。

**程序化装配体**:一个由代码写成的参数化程序,物体拆解成若干个带名字的零件模块,零件之间通过一种叫做"配合"的关系相互连接和定位。

这个设计最直接的好处是,零件划分不再需要额外一步分割模型来补救,因为程序本身写的时候就是一个模块对应一个零件,这个划分是天生自带的,不产生任何额外成本。

配合关系是这套系统里最关键的一个抽象。研究者从工业设计中的装配工程学里借鉴了一套思路:真实世界里两个机械零件要严丝合缝地拼在一起,靠的从来不是随便焊一下,而是有固定套路的连接特征,比如一个凸出的销钉插进一个凹陷的插座,或者一圈螺栓孔对齐另一圈螺栓孔。

**配合库**:Procedura定义了九种静态配合特征,包括座面、螺栓阵列、销钉插座、法兰、卡槽、过盈配合、卡扣、止口和键槽,外加三种运动配合,旋转、滑动和球铰。每一种配合类型都规定了两个零件之间该有多少自由度,公配合定死零件的位置,动配合则精确留出该有的那部分自由运动。

这里有个设计细节特别值得说:配合的两个半边,永远从同一个参数衍生出来,加上一个正负号表示的间隙偏移量,绝不允许分别写死成两个孤立的数字。为什么这么较真?

想象你在装修房子的时候留门框和门的尺寸,如果门框宽度和门的宽度是两个完全独立填写的数字,哪天你想把门改窄一点,只改了门的尺寸,门框却忘了同步改,门就直接装不进去了。Procedura把这两个尺寸绑死在同一个参数上,改一次两边同时联动,这就从代码结构上杜绝了"改了一半忘了另一半"的低级错误。

如果不这么设计会怎样?后果就是每次编辑零件都可能悄悄破坏原本能拼接的接口,而这种错误往往要等到编译渲染出来才会暴露,届时已经很难定位到底是哪个参数出的问题。

一次只写一个零件,边写边核对

有了配合这套语言之后,Procedura真正解决"一次性想清楚太难"这个问题的手段,是把整个建模过程拆成一步一步来。

具体流程是这样的。系统先根据文字提示生成一张参考图,然后调用一次视觉理解能力,把物体拆解成一份有序的零件清单,每个零件都带着简洁的名字、粗略的细节级别,还标注了它要靠哪种配合方式接到哪个已经存在的零件上。这份清单本质上是装配图的一个拓扑排序,保证后面盖房子的时候,每一块砖都踩在已经砌好的地基上。

清单出炉后还有一道"只能加不能减"的审核。第二次视觉调用可以给清单打补丁,添加漏掉的零件、把某个描述写得更精确,但绝对不允许合并、删除、重命名或者调整顺序。

为什么定这么死的规矩?因为在Procedura的架构里,每个零件对应恰好一次生成调用,如果审核阶段把两个零件合并成一个,那么原本该由两次调用分别雕琢的细节,就被压缩进了一次调用里,细节反而变少了。这个约束不是靠提示词里嘱咐模型"请不要合并"来保证的,而是直接写进了代码逻辑里强制执行。

清单定下来之后,真正的建造阶段开始,一次只写一个零件。

每次生成调用,模型看到的东西被称为动态上下文,具体包含三块:装配参考,也就是最初那张参考图、文字描述,还有这个零件该怎么跟谁配合;建造历史,就是目前为止已经编译通过的全部代码;三维反馈,是从最多十二个视角渲染出来的、已经拼好部分的彩色渲染图,每个已经装上的零件都有自己独特的颜色。

这个设计带来的变化非常直观。模型写下一个零件的时候,看得见前面搭好的所有零件长什么样、在哪个位置,就像木匠师傅在一个已经立好骨架的房子里添加新构件,随时能看一眼房梁的实际位置,而不是凭图纸想象。

摆放位置这件事,Procedura干脆不让语言模型来猜。它让模型只负责写零件的几何形状和该零件上要发布的配合坐标系,具体的空间变换是通过一个明确的数学公式,把新零件的配合坐标系和已放置零件的配合坐标系对齐算出来的。

这一步的意义远比听起来重要。此前的三维代码生成系统,普遍让模型直接从一张渲染图里估算一个零件该往哪儿摆,这种"凭眼睛估计坐标"的做法正是漂移和错位的最大来源。Procedura把这一步从"猜"变成了"解方程",彻底堵死了这个误差源头。

零件生成之后,还必须闯过三道验证关卡才能被正式采纳进最终装配体。第一关是编译门,代码编译不过直接把报错信息喂回去让模型重写。第二关是配合门,在编译出的真实网格上量出每个配合处两个零件表面接触的面积和相互穿插的深度,面积太小说明只是悬空挨着没真正贴合,穿插太深说明零件互相打架,两种情况都会被拒收,而且量出来的具体数值会反馈给模型指导它重写。第三关是连通性门,专门盯着那种"看起来接上了、实际上和主体压根没连着"的漂浮零件。

**连通性检测**:把编译出的网格按共享边分成若干连通片,找出跨度最大的那块作为主体,其余部分如果跨度占比达到某个阈值就被判定为可见的漂浮物,整个装配体只有当没有漂浮物时才算通过检查。

这里有个特别有意思的技术选择。研究者一开始尝试用体积来判断零件有没有真正连上,结果发现根本行不通:一块薄薄的平面挡板,包裹的体积几乎为零,用体积判断会误判成"没问题",可它的跨度可能覆盖了大半个模型,肉眼一看就是明显悬空的。所以团队改用跨度而不是体积来衡量,因为跨度衡量的才是人眼和后续审核实际会注意到的东西。

找了个"不知情"的审核员来挑错

零件都拼好之后,Procedura还有一道打磨工序,靠的是一个和写代码的模型彻底分开的独立审核角色。

这一步的设计哲学很值得琢磨。团队没有让同一个模型自己审查自己写的代码,而是专门找了另一次独立调用来当裁判。原因很朴素:一个模型如果自己检查自己的作品,它脑子里犯错误时的那套假设还在,很容易对着自己的盲点视而不见。研究里引用的一篇论文早就指出过,大语言模型往往连自己的推理错误都发现不了。

这就好比你写完一篇稿子自己校对,容易把错别字读成对的,因为你脑子里的"应该是什么"已经替代了眼睛看到的真实文字,非要拿给一个完全没读过你草稿的人重新审一遍,才容易挑出漏洞。

这个独立审核员每次只看渲染图、参考图和零件颜色图例,给出一句话总结,再列出一份按优先级排序的问题清单,每条问题标注严重程度,指名道姓地说是哪个零件出的问题,还给出一句话的修改方向。系统随后严格按照"先诊断、再修一处"的节奏推进,而且强制规定一次诊断只能触发一次修改,修改工具在没有新鲜诊断结果之前会直接拒绝执行。

团队做了个对照实验来验证这条规则的必要性:如果去掉这个强制配对机制,模型会在一次诊断之后连续发起十五次修改,而正常的配对机制下诊断和修改的比例稳定在大约一比一。这说明什么?说明如果放任模型自由发挥,它会不断依据一份早已过时的诊断意见反复修改,越改越偏,而强制配对相当于给它上了紧箍咒,逼它每改一次就重新看一眼最新情况。

同一份图纸,还能自动上色、还能真的动起来

零件清单和配合关系这套结构,不只是拿来搭骨架的,Procedura还顺手把材质和运动都做了出来,而且几乎没有额外成本,因为需要的信息本来就在装配图里躺着。

材质这一步分四次单独的视觉调用完成,不再走前面那套带循环的智能体流程。系统先看着参考图整理出一份材质库,通常二三十种物理渲染材质条目,包括反照率、粗糙度、金属度这些参数,然后把材质库里的条目逐一分配给每个零件,最后同样找一个独立的审核角色来核对分配得对不对。如果一个零件里其实混杂了好几种材质,比如轮胎既有橡胶胎面又有金属轮毂,系统还会把这个零件拆成几个共享同一造型但材质不同的小色块,而且严格保证拆分前后三角面片数量不变,确保颜色分家不会顺带改变了形状。

运动这一块更能体现配合这个抽象的威力。装配体里那些标记为旋转、滑动或者球铰的配合关系,天然就是一副运动骨架,不需要另外再造一套结构来表达关节。系统先用几何方法量出每个零件的旋转对称轴和接触区域,再靠一次视觉调用把零件分组成刚性连杆、规划出父子关节树,给每个关节配上轴线、限位和驱动方式,最终导出成通用的三维场景格式和机器人描述文件格式,直接丢进物理仿真引擎里做验证。

**Isaac Sim**:一款用于机器人和物理仿真验证的软件平台,本文中被用来对Procedura生成的关节结构做真实物理约束下的动态测试,包括让物体静止沉降、逐个驱动关节转动、检测静止状态下是否有零件互相穿模,以及把导出的文件重新导入验证格式是否正确。

这套流程测试过十八个物体,十四个通过了全部物理测试阶段,其中九个还额外通过了更严格的建议性规则检查,剩下失败的四个案例里有一个是文件本身加载不了,另外三个是驱动电机始终没能让关节转动到指定角度。这个数据说明Procedura的运动生成不是拍脑袋编出来的,而是真的能在物理仿真里跑通,这在此前的三维代码生成系统里是不存在的验证环节。

结果打出来怎么样

Procedura团队在两个基准上做了评测。一个是自建的MechBench-36,三十六个刻意选出来的、零件数量特别多的机械物体,比如火星车、机甲、起重机、挖掘机;另一个是已有的P3D-Bench评测集里的装配任务,两百零三个文字加图片的案例。

为了保证评测公正,所有方法生成的结果都统一在同一套灰色渲染环境下重新渲染,方法名字被打上哈希隐藏,由一个独立的视觉语言模型盲评,分别打出几何质量、美学质量和语义准确度三个分数。

在MechBench-36上,Procedura用Gemini 3.7 Flash拿到综合分0.828,是所有参赛方法里最高的,同时在几何和美学两个维度都单独领先,而且36个案例全部成功出模型,一个没漏。紧随其后的原生三维生成器TRELLIS.2拿到0.810,专门做三维代码生成的Adam CAD拿到0.799。而两个专门针对单一草图拉伸的CAD代码模型CAD-Coder和cadrille,在这种多零件机械上直接崩了,分数只有0.135和0.092,因为它们训练时只学过画一个简单的草图拉伸体,根本不会表达一整套装配体。

边缘锐利程度这个指标上差距最直观。Procedura用GPT-5.6生成的模型,锐利边缘总长度达到185.18个单位,是排名第二的代码生成方法的三倍多。原生生成器普遍卡在30到70这个区间,因为从采样点回归出来的曲面根本没有"平面"和"棱边"这个概念。TRELLIS.2的锐利边缘长度倒是凑到了134,但它对应的二面角只有73度,说明那些看起来锐利的棱边其实很浅,远不如Procedura那种由两个精确平面相交出来的真正尖锐棱角。

**二面角**:两个相邻平面之间的夹角,机械零件上真正的棱边通常接近九十度或更陡,越接近这个角度说明这条边越锐利越"硬"。

拿掉配合驱动的建造流程,只让模型一次性写完整个物体,会发生什么?团队专门做了这组对照实验,去掉规划阶段之后综合分从0.828掉到0.791,美学分掉得最厉害;去掉修图打磨阶段掉到0.800;去掉三维渲染反馈掉到0.819。每去掉一个环节,五项指标全线下滑,没有一个环节是可有可无的摆设。

在P3D-Bench上结果类似,Procedura用Gemini 3.7 Flash的综合分是0.590,用GPT-5.6-sol是0.575,都明显高于同一个基础模型不经过Procedura流程、只单次生成一次的表现,分别是0.566和0.563。差距最大的一项恰恰是几何质量,Procedura拿到0.490,单次生成只有0.458,这正好对应着配合驱动建造这套机制主要在解决的问题。

写在后面

读到配合两个半边共享同一个参数这个细节的时候,我想到的其实不是三维建模,而是软件工程里常说的"单一数据源"原则,一份信息只存一处,其他地方都是引用而不是拷贝。Procedura把这个原则用在了几何尺寸上,用代码的方式确保了一件本该由人类工程师小心维护的事情,变成了结构上不可能出错的事情。这提醒我,很多领域里那些看似复杂的可靠性问题,答案往往不是让执行者更小心,而是重新设计一下数据该怎么流动。

论文里那个连通性检测从体积改成跨度的细节,我反复看了好几遍。一个薄薄的挡板体积接近零却横跨大半个模型,这种反直觉的失效案例,恰恰说明设计评测指标的时候,最容易犯的错误就是选了一个数学上干净但和人类实际感知脱节的量。这个教训其实适用范围很广,不管是评测三维模型还是评测任何生成内容,度量标准选得对不对,往往比模型本身强不强更容易被忽略。

Procedura目前的局限也写得很坦诚:智能体只能通过渲染图片来"看"自己搭的东西,遮挡在内部的接触细节可能永远藏在每一个摄像机角度之外;CSG这种由平面和圆柱构成的几何语言,天生适合机械零件,但要它表达一件毛绒玩具或者一朵花,可能就没那么自然了。这两个局限会不会催生出下一代把渲染反馈换成直接查询三维网格数据的系统?这个问题现在还没有答案。

Q&A

Q1:Procedura是什么?

A:Procedura是南京大学团队提出的一种三维建模智能体框架,它让冻结不变的大语言模型把三维物体写成一段带零件划分和配合关系的程序代码,而不是直接生成网格,从而兼顾高精度几何、清晰的零件结构和可编辑性。

Q2:Procedura和普通的三维生成模型有什么区别?

A:普通三维生成器直接输出一整块网格曲面,棱角圆润且没有零件划分,编辑困难;Procedura输出的是参数化程序,零件天然带名字和可调参数,边缘锐利,还能一步导出材质和可动关节结构。

Q3:Procedura生成的模型效果好在哪些方面?

A:在MechBench-36和P3D-Bench两个评测基准上,Procedura在几何质量、美学质量上都超过了当前最强的原生三维生成器和此前所有三维代码生成智能体,同时是唯一输出可编辑、按零件结构组织的程序化结果的方法。