1. 项目缘起:当AI遇到3D建模,一个“不务正业”的尝试
最近在折腾一个挺有意思的玩意儿,起因其实挺简单:我手头有个小项目,需要快速生成一些结构简单的3D零件模型,用于初步的装配验证。按理说,打开熟悉的CAD软件,画草图、拉伸、打孔、倒角,一套流程下来,一个零件怎么也得花上十几二十分钟。但那天我就在想,现在AI连代码都能写了,能不能让它也来“理解”一下我的建模意图,帮我省点事儿?
这个念头一冒出来就有点收不住。我试过直接让ChatGPT描述一个零件的建模步骤,它确实能给出“先画一个直径50mm的圆,然后向上拉伸20mm”这样的指令,但这离真正的建模还差得远。我也试过一些所谓的“AI生成3D模型”的在线工具,它们要么是生成一些无法编辑的、像雕塑一样的网格模型,要么就是功能极其有限,离工程上用的参数化建模(Parametric Modeling)差了十万八千里。参数化建模的核心是什么?是尺寸驱动、是特征历史、是父子关系,是修改一个参数,整个模型能智能地跟着变。现有的AI工具,似乎还没怎么碰这块硬骨头。
于是,一个有点“疯狂”的想法诞生了:能不能自己搭一个桥,让AI的自然语言指令,直接驱动一个真正的参数化建模内核,生成可编辑、带历史、完全符合工程标准的3D CAD模型?说干就干,我花了两个晚上,从构思到实现了一个最基础的原型,并决定把它开源出来。我管它叫“AI驱动的实时3D CAD / 参数化建模工作台”。本质上,它是一个将大语言模型(LLM)与开源CAD几何内核连接起来的“翻译器”和“执行器”。
2. 核心架构拆解:AI如何“理解”并“执行”建模命令
这个项目的核心挑战,在于如何让两种完全不同的“语言”进行对话。一边是人类的自然语言(比如“创建一个长100mm、宽50mm、高20mm的长方体,在顶面中心打一个直径10mm的通孔”),另一边是CAD软件底层严格的API调用和几何运算指令。我的解决方案是一个典型的三层架构。
2.1 交互层:从自然语言到结构化意图
首先,我们需要一个界面来接收用户的指令。我选择了一个极其简单的Web前端,就是一个输入框和一个3D视图区。用户在这里输入描述,点击执行。前端的工作很简单,就是把这段文本发送给后端服务。
真正的魔法发生在后端。我使用了一个开源的大语言模型API(具体模型可以根据需要切换,比如GPT-4、Claude或者开源的Llama 3)。但直接让AI输出CAD代码是行不通的,因为太容易出错,且不可控。我的策略是:让AI先做“翻译官”和“规划师”。
我设计了一套结构化的“建模意图描述”JSON Schema。当后端收到用户指令后,会将其连同这个Schema描述一起发送给LLM。Prompt大致是这样的:“你是一个CAD专家。请将用户的需求,解析并填充到以下JSON结构中。这个结构描述了一个分步的建模操作序列。”
这个JSON Schema定义了建模的基本单元“操作”(Operation)。每个操作包含:
type: 操作类型,如sketch(草图)、extrude(拉伸)、revolve(旋转)、hole(打孔)、fillet(倒圆角)等。parameters: 该操作的具体参数,这是一个对象。例如对于sketch,可能有plane(草图平面)、entities(图元列表,如线段、圆等及其约束和尺寸);对于extrude,有profile(要拉伸的草图)、distance(距离)、operation(是“加材料”还是“减材料”)。
LLM的任务,就是把“创建一个带孔的长方体”这样的模糊描述,翻译成一个如下的JSON数组:
[ { “type”: “sketch”, “parameters”: { “plane”: “XY”, “entities”: [ {“type”: “rectangle”, “center”: [0, 0], “width”: 100, “height”: 50} ] } }, { “type”: “extrude”, “parameters”: { “profile_ref”: 0, // 引用第0步创建的草图 “distance”: 20, “operation”: “add” } }, { “type”: “sketch”, “parameters”: { “plane”: “face”, // 在某个面上 “face_ref”: 1, // 引用拉伸生成的长方体顶面 “entities”: [ {“type”: “circle”, “center”: [0, 0], “diameter”: 10} ] } }, { “type”: “extrude”, “parameters”: { “profile_ref”: 2, “distance”: -20, // 负值表示反向,打穿 “operation”: “subtract” } } ]这个过程我称之为“意图解析”。它有几个关键好处:第一,它将非结构化的语言转化为了机器可精确理解的结构化数据;第二,它强制AI进行“分步思考”,符合CAD建模的流程逻辑;第三,这个JSON中间层成为了前后端、以及不同CAD内核之间解耦的关键。
2.2 逻辑层:结构化意图到CAD内核API的映射
拿到结构化的操作序列JSON后,下一步就是执行。这里我引入了项目的第二个核心组件:参数化建模内核。我没有选择从头写一个几何引擎,那是个无底洞。经过调研,我选择了Open CASCADE Technology (OCCT)。它是一个功能强大、成熟的开源C++几何内核,是许多商业CAD软件(如FreeCAD)的底层基础。它提供了从基础图元到复杂布尔运算、曲面建模的一整套API。
我的逻辑层(用Python实现,通过PythonOCC绑定调用OCCT)就是一个“翻译器”。它读取上一步生成的JSON操作序列,然后将其映射为一系列对OCCT API的调用。
例如,当遇到{“type”: “sketch”, …}时,翻译器会:
- 根据
plane参数,在OCCT中创建对应的坐标系平面。 - 遍历
entities列表,调用OCCT的API创建对应的几何对象(gp_Pnt点,gp_Lin线,GC_MakeCircle圆等)。 - 根据
constraints(约束,如垂直、相切)和dimensions(尺寸),调用OCCT的约束求解器(如GCE2d_Make*系列类)来定位和定型这些图元,最终形成一个封闭的“轮廓”(TopoDS_Wire)。
当遇到{“type”: “extrude”, …}时,翻译器会:
- 根据
profile_ref找到对应的轮廓。 - 调用
BRepPrimAPI_MakePrismAPI,根据distance和direction进行拉伸。 - 根据
operation是“add”还是“subtract”,将新生成的实体(TopoDS_Shape)与之前的历史模型进行布尔运算(BRepAlgoAPI_Fuse或BRepAlgoAPI_Cut)。
这个逻辑层还负责维护一个建模历史树。每一个操作步骤,不仅产生了最终的几何体,还记录了其输入参数和生成的中间形状。这是实现参数化最关键的一环。当用户说“把那个孔的直径从10mm改成15mm”时,系统不需要重新解析整个句子,而是可以:
- 定位到历史树中对应的“打孔”操作节点。
- 修改该节点参数中的
diameter值。 - 从该节点开始,重新执行后续所有依赖于此孔尺寸的操作(比如如果有个倒角依赖于孔的边,倒角也会自动更新)。
2.3 呈现层:实时可视与交互反馈
最后,生成的3D模型需要实时显示给用户。我使用了Three.js这个强大的WebGL库来在浏览器中渲染3D图形。逻辑层在每次操作执行后,会将OCCT生成的TopoDS_Shape(边界表示模型)进行网格化(Tessellation),转换成Three.js可以理解的顶点和面数据,并通过WebSocket或HTTP接口发送给前端。
前端Three.js接收到新的网格数据后,更新场景,用户就能立刻看到建模结果。我特意实现了基础的交互:旋转、缩放、平移视图,以及高亮显示当前选中的特征。例如,当用户说“选中那个圆柱体”,AI在解析时可以将“圆柱体”映射到历史树中的某个特征ID,前端收到指令后就能高亮对应的几何体。
整个流程形成了一个闭环:用户描述 -> AI解析为结构化序列 -> 逻辑层映射为CAD内核API执行 -> 生成网格数据并实时渲染。这个原型虽然简单,但完整地验证了“AI驱动参数化建模”的可行性。
3. 关键实现细节与踩坑实录
把想法变成代码的过程,充满了“惊喜”。下面分享几个让我印象深刻的实现细节和踩过的坑。
3.1 约束与尺寸的“模糊”处理
在草图阶段,最大的挑战是约束和尺寸。人类的描述往往是模糊的。“画一个矩形”默认是水平竖直的边。“在中心打一个孔”,“中心”这个概念需要AI根据上下文推断——是矩形的几何中心?还是 bounding box 的中心?对于简单图形,可以定义规则。但复杂草图就麻烦了。
我的策略是分层处理:
- 几何图元优先:让AI先输出基本的几何元素(线、圆、弧)及其近似的参数。比如“一个大概边长50的矩形”,AI可以输出一个中心在原点、边长50的正方形草图,不带约束。
- 约束后置求解:在逻辑层,我实现了一个简单的“自动约束推测”模块。当草图图元被创建后,这个模块会分析图元间的几何关系(比如两条线是否近似平行或垂直,点是否近似在线上),然后自动添加相应的几何约束(平行、垂直、重合等)。这模仿了现代CAD软件“智能捕捉”的行为。
- 尺寸驱动覆盖:最后,将AI解析出的精确尺寸(如“边长50”)作为强约束施加到草图上去,覆盖掉之前近似创建时的参数。OCCT的约束求解器会据此调整草图,满足所有约束。
注意:这里的“自动约束推测”是一把双刃剑。它极大地提高了从自然语言到可用草图的成功率,但也可能引入意想不到的约束,导致后续修改时出现“过约束”错误。在开源版本中,我选择保留这个功能,但给出了明确的日志输出,告诉用户自动添加了哪些约束,方便高级用户调试。
3.2 历史树的重算与性能陷阱
参数化建模的魅力在于“牵一发而动全身”,但这也意味着性能开销。我的第一个 naive 实现是:每次修改早期参数,都从头开始执行整个操作序列。对于一个只有几步的模型没问题,但如果操作步骤积累到几十步,每次修改都要重算,体验会非常卡顿。
优化方案是引入脏标记和局部重算。我为历史树中每个节点(对应一个操作)都添加了“脏”(Dirty)状态。当某个节点的参数被修改,该节点及其所有下游依赖节点都会被标记为“脏”。重算时,系统从最上游的“脏”节点开始执行,其结果会自动传递给下一个“脏”节点,直到所有“脏”状态被清除。非“脏”节点则直接使用缓存的结果。
然而,这里有个OCCT相关的深坑:形状(TopoDS_Shape)的共享与复制。OCCT中,形状是通过句柄(Handle)管理的。如果简单地在一个节点修改了某个形状,而这个形状又被下游节点引用,可能会导致意想不到的联动修改或崩溃。正确的做法是,在每个操作节点执行时,如果其输入形状可能被修改,就需要对其进行深拷贝(TopoDS_Shape的Copy()方法),确保操作间的数据隔离。我花了大量时间调试一些诡异的模型错乱问题,最终根源都指向了形状引用管理不当。
3.3 AI提示工程:少即是多
让LLM输出完美的结构化JSON,极度依赖提示词(Prompt)的设计。我走过弯路,一开始把整个OCCT的API手册都快塞进Prompt了,希望AI能“更专业”,结果反而导致输出不稳定、速度慢且容易“幻觉”。
后来我总结出针对CAD场景的提示词设计原则:
- 角色定义清晰:“你是一个严谨的机械设计工程师,擅长将模糊的需求转化为精确、可执行的CAD操作步骤。”
- 输出格式严格:明确给出JSON Schema,并强调“只输出JSON,不要有任何额外解释”。
- 知识范围限定:在System Prompt中,只提供本项目支持的操作类型列表(sketch, extrude, hole, fillet…)和每个操作允许的参数,不要展开讲几何原理。
- 示例驱动:提供2-3个从简到繁的完美示例(Few-Shot Learning)。比如示例一:“创建一个半径为20的球体。” 示例二:“创建一个长100宽50高20的长方体,然后在顶面距离一条边20mm的位置打一个直径10mm深15mm的盲孔。” 这比千言万语都有效。
- 鼓励分步:在Prompt中明确要求“请将复杂操作分解为多个顺序执行的基本操作步骤”。
经过这样的优化后,LLM的输出准确率有了显著提升。它更像一个遵循固定流程的“制图员”,而不是天马行空的“艺术家”,而这正是工程领域所需要的。
4. 开源工作台的现状、局限与未来可能
目前开源在GitHub上的版本,是一个功能完整但略显粗糙的“概念验证”(Proof of Concept)。它包含了上述的所有核心模块:一个简单的Flask后端、与LLM API的集成、基于PythonOCC的CAD内核调用层、以及一个Three.js前端。
它能做什么?
- 通过自然语言创建基本几何体(盒体、圆柱、球体、圆锥)。
- 进行拉伸、旋转、扫掠等基础特征操作。
- 实现简单的打孔(通孔、盲孔)、倒角(圆角、斜角)。
- 支持基于历史树的参数修改(比如“把圆柱的直径从30改为40”)。
- 在浏览器中实时显示和交互。
它的局限性也很明显:
- 草图能力弱:目前只支持非常简单的矩形、圆形草图,缺乏复杂的轮廓绘制和约束定义能力。
- 特征库有限:像筋板、放样、曲面、阵列等高级特征尚未实现。
- AI理解边界:对于非常复杂或模糊的描述(如“设计一个看起来流线型的支架”),AI无法处理。它擅长执行精确指令,而非创意设计。
- 性能与稳定性:作为原型,未经过深度优化,处理复杂模型时可能会有性能瓶颈。OCCT的异常处理也需要更完善的封装。
- 无本地模型:目前依赖云端LLM API,存在延迟、成本和隐私考虑。
那么,这个项目的意义何在?我认为它打开了几扇门:
- 教育演示价值:对于学习CAD原理或参数化设计的学生,这是一个绝佳的、可视化的教学工具。你可以用语言“指挥”建模过程,直观地看到每个特征是如何一步步添加的,历史树是如何构建的。
- 快速原型与自动化:对于需要批量生成系列化零件(如不同尺寸的螺栓、齿轮)的场景,可以编写脚本调用这个工作台的API,实现自动化建模。或者,为复杂的标准件库提供一个自然语言的查询和生成接口。
- 辅助设计起点:设计师可以快速用语言勾勒出概念模型的大致形状和主要特征,得到一个基础参数化模型,然后再导入专业CAD软件进行精细加工。这大大降低了从“想法”到“初步模型”的门槛。
- 探索新的交互范式:它证明了“语言+参数化”这种交互方式的可行性。未来是否可以结合语音输入、手势识别,形成多模态的CAD交互界面?
开源这个项目,是希望抛砖引玉。CAD软件发展了数十年,交互方式(菜单、工具栏、鼠标)基本定型。AI的爆发提供了一个重新思考人机交互的机会。我这两天的“倒腾”只是一个起点,我相信,未来真正强大的AI辅助设计工具,不会是简单地替代设计师,而是会成为设计师手中一支更听话、更智能的“笔”,将创意从繁琐的操作中解放出来,更聚焦于设计本身。这个工作台的代码就在那里,欢迎任何对CAD、AI或两者交叉领域感兴趣的朋友一起“倒腾”,让它变得更好用。