程序化建模实战:让AI写代码生成可靠3D模型

发布时间:2026/9/8 4:22:48
程序化建模实战:让AI写代码生成可靠3D模型 先讲个真实经历。上个月我需要一个带法兰边的异形管道接头第一反应是让 AI 直接生成 3D 模型。折腾了半小时模型倒是“像那么回事”但一导入工程软件就露馅面是碎的、尺寸标注全是小数、布尔运算之后甚至出现悬空点。我换了个思路让 AI 写一段生成这个零件的 Python 代码结果十分钟出了一版参数化模型改内径、改法兰厚度只需要改两个数字。这篇文章就是想把整个思路和实操过程拆开讲清楚说说为什么“让 AI 写代码”比“让 AI 吐模型”靠谱得多以及你该怎么把这套方法落地。这个主题适合三类人被 AI 直出模型坑过的设计师、想给建模流程引入程序化思路的工程师、以及正在学 AI 编程但不知道能用在什么实际场景的开发者。前 80% 的内容是思路和避坑后 20% 是可直接抄走的代码。1. 别让 AI 直接“倒模”直出模型在真实工期的四个翻车现场我先不急着夸“写代码”的路线而是把“AI 直接吐模型”这件事按场景拆开你才能理解后面所有方法为什么要那样设计。1.1 游戏资产拓扑和面数是硬伤游戏行业对模型的要求不是“像”而是“省”。一个场景里几百个物件每个物件几千个三角面已经是极限次世代资产也得控制在几万面以内。AI 直接生成的模型尤其是通过图片重建或者文生模型管线出来的 Mesh普遍存在两个问题拓扑结构混乱。三角面走向完全没有规律贴图的时候 UV 拉伸得一塌糊涂。面数不可控。同一个茶壶AI 生成出来可能是 80 万面也可能是 8 万面你没法让它“按预算布线”。这两个问题在程序化建模里根本不存在。代码生成的模型每一个顶点、每一条边都是逻辑推导出来的你完全知道它长什么样、有多少面。1.2 机械件和工程件尺寸公差根本对不上有一次我需要一个 M8 螺母的模型做装配演示。AI 给了一个“看起来很像”的六角体但内径画成了 7.2mm而不是螺纹中径对应的小径对边距离也不是标准值。在游戏里这无所谓但如果是做 3D 打印或者 CNC 加工这种模型直接废掉。AI 直出模型最大的问题就是它不懂工程语义不知道什么是公差、什么是配合间隙、什么是基准面。它只是把训练数据里的“螺母图片”或“螺母模型”的统计特征模仿出来了。1.3 3D 打印破面与封闭性问题排查到怀疑人生3D 打印软件切片时要求模型必须是封闭的流形也就是“水密”的。AI 生成的模型经常有开口边、重叠面、反向法线。你用软件自动修复有时候越修越乱。上回一个朋友让我帮看一个 AI 生成的摆件模型光修复破面就花了两个小时最后发现缺口处有十七个重合顶点这已经不是“修”能解决的事只能重新拓扑。1.4 非标准几何AI 只能“画得像”没法“算得对”你可以让 AI 直出一个“一朵抽象化的花”这个它擅长。但你要是让它生成“一个半径为 30 的圆弧过度到半径为 8 的孔再绕中心轴阵列为 12 个”的零件它就傻眼了。因为这种需求本质上是参数约束不是像素和网格层面的拟合。AI 直出模型是“画得像”程序化建模是“算得对”这是两种完全不同的建模哲学。2. “写代码生成模型”到底是怎么工作的把建模变成可执行的逻辑既然 AI 直出模型不靠谱那“让 AI 写代码”具体又是什么这里需要把程序化建模Procedural Modeling这个概念讲透。2.1 从“手工捏形”到“程序生成”换个视角看建模传统手工建模你的工具是鼠标、键盘、数位板你的原材料是点、线、面。程序化建模你的工具是代码你的原材料是数字——长度、角度、数量、半径、偏移量。你告诉程序“画一个半径 20 的圆拉伸 5 毫米在圆周上阵列 8 个直径 4 的孔”它就精确地生成这样一个实体。很多设计师一听“编程”两个字就头大但其实你天天用的 SolidWorks、Fusion 360、Blender底层都是这么干的。SolidWorks 里改一个草图尺寸整个零件跟着变这就是参数化思路。代码只是把这个思路彻底开放了——你不受界面按钮的限制任何几何关系都可以用数学表达。2.2 程序化建模适合什么场景不适合什么场景程序化建模不是万能的。它擅长有规律、可复用的几何机械零件、建筑构件、管道系统、齿形、螺纹、散热片阵列、编织结构。它不擅长有机形态人脸、动物、自然景观。但这些不擅长的领域AI 直出模型其实也做不好看——当然那是另一个话题。最适合程序化建模的场景有一个共性你需要的不是一个模型而是一族模型。比如同样一款法兰内径要适配 DN15、DN20、DN32 三种管径。手工建模你要建三个程序化建模你只需要改一个变量运行三次。2.3 技术选型对比Blender Python、CadQuery、OpenSCAD、Trimesh“让 AI 写代码生成 3D 模型”的关键是选对执行环境。我试过几个主流方案分别说下感受方案擅长领域适合人群上手成本Blender Python (bpy)多边形建模、做动画资产游戏美术、设计师中CadQuery精确机械建模、STEP 导出机械工程师中高OpenSCAD纯代码建模极客风格创客、3D 打印玩家低Trimesh网格分析和处理开发者、算法工程师中我个人最常用的是 CadQuery因为它的建模逻辑是“布尔 拉伸 扫掠”和机械设计直觉一致而且能直接导出 STEP 这种带精确曲面数据的工业格式。Blender Python 更适合做视觉效果类的东西导出的 STL/OBJ 在工程软件里往往还需要再做处理。OpenSCAD 语法很简单但几何能力偏基础复杂的圆角过渡不好做。Trimesh 不是建模工具更多是加载、处理、分析模型用的库适合做自动化流程里的中间环节。3. 实测一条可行的落地链路AI 写 Python 代码程序化生成参数化零件这一节是全文的实操核心。我会用一个真实的参数化法兰盘例子完整演示“让 AI 写代码生成 3D 模型”的链路。3.1 给 AI 下需求怎么写提示词它才能产出可运行代码先给大家看看我第一次是怎么写的以及为什么被坑了“帮我生成一个法兰盘”这种描述给到 AI它可能会给你一段看起来很优美但实际上跑不起来的代码或者一堆不存在的 API。原因是建模代码必须精确描述几何参数和操作顺序你没给参数它就只能瞎猜。经过反复试错我整理出一套好用的提示词结构明确建模目标要生成什么零件。给出全部关键参数外径、内径、厚度、孔的数量、孔的位置。明确单位毫米还是英寸。指定输出格式导入 STEP 还是 STL。说明约束条件比如“所有孔必须均匀分布在分度圆上”。按这个结构我写给 AI 的提示词是这样的使用 CadQuery 生成一个法兰盘 - 外径 100mm法兰厚度 12mm - 中心孔直径 34mm - 分度圆直径 80mm上有 4 个螺栓孔孔径 9mm - 单位是毫米 - 最后导出为 STEP 文件文件名为 flange.step这段描述只占屏幕三行但信息量已经足够让 AI 生成一段基本可用的代码。3.2 核心代码拆解以参数化法兰盘为例下面这段代码是 AI 生成的我做了少量修正后实测通过import cadquery as cq # 参数定义 flange_od 100 # 法兰外径mm flange_id 34 # 中心孔直径mm flange_th 12 # 法兰厚度mm bolt_circle_d 80 # 分度圆直径mm bolt_hole_d 9 # 螺栓孔径mm bolt_count 4 # 螺栓孔数量 # 创建法兰主体 result ( cq.Workplane(XY) .circle(flange_od / 2) .extrude(flange_th) .faces(Z) .workplane() .hole(flange_id) ) # 在分度圆上生成螺栓孔 for angle in range(0, 360, int(360 / bolt_count)): x bolt_circle_d / 2 * cos(radians(angle)) y bolt_circle_d / 2 * sin(radians(angle)) result ( result.faces(Z) .workplane() .center(x, y) .hole(bolt_hole_d) ) # 导出 STEP cq.exporters.export(result, flange.step)里面有几个容易踩坑的地方需要特别说明faces(Z)表示选中顶面作为下一个操作基准面这是 CadQuery 里非常核心的链式操作逻辑。很多人写代码时漏了这一句导致孔打在底面或者侧面。range(0, 360, int(360 / bolt_count))这种写法其实有隐患当螺栓孔数量不是整数时会导致角度不均。正确的做法是直接用range(bolt_count)然后通过angle 360 / bolt_count * i计算角度。后来我把这个坑反馈给 AI它自己也承认写法不够严谨。hole()方法默认是从当前工作平面向下打孔如果你选中的是顶面打出来的孔会贯穿整个实体。这一步没问题但新手容易在.center(x, y)之后忘记重新选中面导致孔的位置叠加在之前的位置上。跑通这段代码之后你会发现一个特别有价值的特性参数化。把bolt_count改成 8把bolt_circle_d改成 95重新运行一个新的法兰就出来了。传统手工建模你可能要改一堆草图的约束代码这边就是改两个数字的事。3.3 验证与修改让 AI 自己修 bug 的方法代码能跑只是一个开始更常见的情况是代码跑通了但模型跟预期不完全一样。这时候很多人会自己去读代码、改代码但我给你一个提效思路把报错信息和实际现象贴回给 AI让它改代码而不是自己硬改。有一次我把法兰厚度改成 20mm 之后螺栓孔不见了。我把模型截图和以下描述扔给 AI法兰厚度改成 20 之后螺栓孔没有穿透只在顶面形成了一个凹坑。请检查代码修正打孔逻辑确保螺栓孔穿透整个法兰厚度。AI 很快就发现hole()的默认深度只与当前工作平面相关厚度过大时孔没有穿透底面。它给出的修正方案是给hole()加一个深度参数或者使用cut() 圆柱体的方式做贯穿切割。这种“现象描述 → 让 AI 改代码”的循环通常两三轮就能把模型修到可用状态。这比让 AI 直接生成模型再手工修复 Mesh 靠谱多了。为什么因为代码出错你能定位到具体某一行而 Mesh 出错你连“哪一步导致的”都说不清。3.4 进阶组合多个零件批量生成装配体单个零件跑通之后你可以进一步让 AI 生成一组配套零件然后组装。比如除了法兰盘再生成一个配套的密封垫圈gasket ( cq.Workplane(XY) .circle(flange_od / 2 2) # 外圈加 2mm .circle(flange_id / 2 - 1) # 内圈缩小 1mm .extrude(2) # 垫圈厚度 2mm )因为两个零件共享同一组参数你只需要改一次上限参数装配体里的所有零件都会同步更新。这种联动式修改手工建模时非常痛苦代码方案里却是天然行为。4. 从“能出图”到“能交付”格式、尺寸、性能的踩坑记录代码跑通只是第一步真正把一个模型变成可交付的资产中间全是细节。这一节把我在真实项目里踩过的坑集中盘一遍。4.1 单位与比例最容易翻车的第一关CadQuery 默认使用毫米这没问题。但如果你在 Blender Python 里写代码Blender 的默认单位是米。一个常见的坑是你让 AI 生成一个“直径 100”的圆柱它默认你在 Blender 里用的单位是米结果导出的模型实际尺寸是 100 米。所以写提示词的时候一定要强制声明“单位是毫米”并且在代码里显式设置单位。如果是 Blenderbpy.context.scene.unit_settings.scale_length 0.001这一行就能把单位从米换算成毫米。4.2 导出格式选哪种STEP、STL、OBJ、GLB 各有各的坑选格式不是一个“随便”的事情我列一张表说明建议格式优点缺点建议使用场景STEP精确曲面带几何邻接关系文件较大机械加工、工程装配STL通用性好3D 打印都认只有三角面无拓扑信息3D 打印OBJ带 UV 和材质信息几何精度低游戏、视觉效果GLB/glTFWeb 友好体积小建模精度有限网页 3D 展示工程交付首选 STEP因为 CNC 和 CAE 软件对 STEP 的支持最完整。3D 打印用 STL 没问题但记得导出前检查模型是封闭的。CadQuery 导出的 STL 一般不会出现破面这一点可比 AI 直出模型省心太多了。4.3 性能观察布尔运算、阵列数量与内存上涨程序化建模有一个隐藏成本运算时间。尤其是涉及大量布尔运算比如给一个大平面上打几百个孔的时候代码会跑得很慢。我做一个测试在一个 200x200mm 的铝板上阵列 144 个直径 6mm 的孔12x12 阵列CadQuery 普通的布尔打孔耗时约 8 秒内存峰值约 1.2GB。优化思路有两条用cq.workplane().rarray(x_count, y_count, x_spacing, y_spacing)批量打孔比循环调用一次一次打要快很多。尽量减少布尔操作次数。同一个平面上规律排列的孔尽量合并成一个“多体布尔”而不是一个孔一个孔地切。如果还是慢可以考虑先用代码生成 2D 轮廓再用 CAD 软件拉伸但这已经偏离本文主题了。4.4 排查链路实例从“导出的模型是空的”说起有朋友跑了一段 AI 生成的代码导出后屏幕上什么都没有但文件确实生成了。这种问题典型的排查链路是这样的先确认代码里模型是否存在于变量中在导出前加一行print(result.volume())如果体积是 0说明模型本来就是空的。再看是不是坐标系建错了比如模型被生成在X100000的位置导入软件后视野里根本看不到。然后再排查导出参数CadQuery 导出 STEP 用的exporters.export第二个参数是文件路径这个没错但如果你export了一个尚未把它赋给任何实体的变量自然导出的是空气。这个排查过程里我最推荐的思路是让问题通过代码暴露出来而不是盯着界面瞎猜。手工建模排查破面你无从下手代码建模排查形状你可以一句一句打印中间结果每一步都清清楚楚。5. 基于个人经验再补充让 AI 持续写建模代码的工作流与下篇预告最后这部分不写教程聊一聊怎么把这套方法融入真实工作流以及还有哪些坑值得提前规避。5.1 用 git 给模型代码做版本管理模型代码也是代码那就该用代码的方式管理。我在本地给每个项目建一个 git 仓库所有.py文件和导出的.step文件都放进去。每次改完代码生成新模型提交一次 commit。这个习惯的好处在于当客户说“还是上一版好看”的时候你不用翻半天历史文件。git log看记录git checkout切回去重新导出就是之前那版模型。AI 直出的模型做不到这一点——它对你的“上一版”毫无概念。5.2 给 AI 一个“上下文包”项目规范、单位约定、命名规则同一个 AI你跟它聊天时它可能会忘记你之前说的单位约定。一个很实用的做法是在项目根目录放一个spec.md说明文件每次让 AI 生成代码之前先把这份规范粘贴给它# 项目建模规范 - 单位毫米 - 坐标系Z 轴朝上 - 命名零件文件名必须包含版本号 - 导出格式STEP, 需检查 volume() 大于 0这看起来是小事但能极大减少来回纠偏的沟通成本。AI 有它自己的“习惯”但你用规范约束它它就能稳定产出符合你要求的代码而不是每次生成一个“看起来对但细节全错”的版本。5.3 后续还能怎么玩AI Agent 自动建模、参数化组件库我已经在实际环境里测试了“AI Agent 自动建模”的工作方式给 Agent 指定一个任务描述比如“生成一个带 6 个螺栓孔的 DN50 法兰外径遵循 GB/T 标准”它会自动查阅标准、生成代码、导出模型然后自我验证尺寸是否符合标准。这一步目前还需要人工复核但已经能省掉 80% 的重复建模时间。另外把常用的零件都做成参数化代码积累成组件库也是一个很值得投入的方向。眼下是法兰、齿轮、固件未来整个设备的非标件都可以走这条路。这样一来新项目启动时你手上不是一堆光秃秃的模型文件而是一套可以随时“重新长出来”的生成规则。就我个人这段时间的实践来看把 AI 用在生成代码而不是直接生成模型上前期看起来绕了弯路实际上省下了大量后期返工的时间。如果你正在被 AI 直出模型的“好看但没法用”折磨建议找个简单的机械零件照这篇文章的方法试一次你会马上体会到“改数字而非改模型”的乐趣。这篇先写到这。下一篇我会详细拆解怎么把 AI 生成代码的流程做成一个可复用的自动化工具链包括我怎么处理布尔运算失败、怎么用脚本批量验证模型尺寸、以及怎么对接现有的 3D 打印切片流程。如果你在复现的过程中遇到什么奇怪的问题欢迎在评论区带上你的代码段和报错信息我看到了都会回。