1. 从一句话到三维模型:text-to-cad 到底在解决什么问题
第一次听到 "text-to-cad" 这个词,很多做机械设计或者工业建模的朋友第一反应是:又来了一个新概念。但如果你真的动手试过把一段文字描述直接变成可用的三维模型,就会明白这件事的分量——它试图砍掉的是从"想法"到"几何体"之间那段最枯燥、最耗时的重复劳动。
传统流程是什么样?你脑子里有一个零件,先要在脑子里把它拆成特征:底座多大、孔位在哪、倒角多少、壁厚几毫米。然后打开 CAD 软件,画草图、拉伸、打孔、阵列、倒角,一步步把脑子里的东西"翻译"成软件能理解的几何语言。这个过程里,真正有创造性的部分可能只占两成,剩下八成都是在跟坐标系、约束关系、尺寸标注较劲。text-to-cad 想做的,就是让你用自然语言把需求说清楚,由系统去完成那八成的机械操作,直接吐出 STEP、GLB、STL 这类标准格式的文件。
它适合谁?我梳理了一下,大致是三类人。第一类是产品经理、工业设计师这类"有想法但不一定精通 CAD 操作"的角色,他们需要快速把概念可视化,拿去跟团队或客户对齐。第二类是机械工程师,日常要处理大量标准件、简单结构件的建模,用 text-to-cad 做初稿能省下大量时间。第三类是搞 3D 打印、创客、教育场景的玩家,他们关心的是 STL 能不能直接切片打印,对建模精度要求没那么苛刻,但对"快"和"简单"要求极高。
这里必须先说清楚一个关键点:text-to-cad 生成的模型,和资深工程师手工精修的模型,在质量上是有差距的。它更像是一个"高质量初稿生成器",而不是"一键替代设计师"。理解这个定位,你才不会对它抱有不切实际的期待,也才能把它用在真正能发挥价值的地方。下面我会从整体设计思路、核心技术细节、完整实操流程、常见问题排查几个维度,把这件事掰开揉碎讲清楚。
2. 整体设计思路:为什么是"文本到几何"这条链路
2.1 从自然语言到参数化特征的映射逻辑
text-to-cad 的核心难点,不在于"生成一个模型",而在于"生成一个符合描述、且几何上合法的模型"。这两者差别巨大。随便生成一堆三角面片很容易,但要生成一个壁厚均匀、孔位对称、能通过基本几何校验的实体,就需要一套严谨的映射逻辑。
我研究过几套主流实现思路,本质上都绕不开一个中间层:把自然语言先解析成结构化的参数化描述,再由参数化描述驱动几何内核生成实体。举个例子,你说"一个 100mm × 60mm × 20mm 的矩形底板,四角各有一个直径 6mm 的通孔,孔中心距边缘 10mm",系统需要先把它解析成这样的结构:
- 基础体:长方体,尺寸 (100, 60, 20)
- 特征1:四个圆柱孔,直径 6,深度贯穿
- 孔位约束:距相邻两边各 10mm
这个结构化描述才是真正驱动建模的东西。自然语言只是入口,参数化特征才是骨架。为什么这么设计?因为几何内核(比如 OpenCASCADE 这类)本身不认识"四角各有一个孔"这种话,它只认识坐标、向量、布尔运算。中间加一层参数化描述,既能让语言解析和几何生成解耦,各自独立优化,也方便后续做校验和修改。
提示:如果你自己要搭一套类似的系统,强烈建议把"语言解析"和"几何生成"分成两个独立模块,中间用一份 JSON schema 约定好接口。我见过太多把两者揉在一起的项目,后期想换个语言模型或者换个几何内核,牵一发动全身。
2.2 输出格式的选择:STEP、GLB、STL 各管什么
热词里反复出现 STEP、GLB、STL,这三个格式不是随便列的,它们对应完全不同的使用场景,选错了会直接导致下游流程走不通。
| 格式 | 本质 | 典型用途 | 是否保留特征/精度 |
|---|---|---|---|
| STEP | 边界表示(B-rep)实体 | 工程交付、CAD 二次编辑、CNC 加工 | 保留精确几何,可参数化编辑 |
| GLB | 三角网格 + 材质 | 网页展示、AR/VR、渲染预览 | 网格化,丢失精确特征 |
| STL | 纯三角网格 | 3D 打印、切片 | 只有面片,无单位无材质 |
STEP 是工程界的"通用语",它记录的是精确的数学曲面,你拿到之后还能在 SolidWorks、中望 CAD 这类软件里继续改尺寸、加特征。GLB 是给"看"用的,带材质和颜色,适合放到网页或者三维预览里给人看效果。STL 是给"打印"用的,它把模型表面全部三角化,切片软件只认这个。
所以一个成熟的 text-to-cad 系统,通常不会只输出一种格式,而是根据用户意图自动选择,或者干脆三种都生成。我的经验是:默认给 STEP,需要预览时转 GLB,需要打印时转 STL。转换方向基本是单向的——STEP 可以转成 GLB 和 STL,但 STL 转回 STEP 只能得到一堆碎面片,特征全丢了。热词里那个"sw中stl转stp"之所以是个高频问题,就是因为很多人不知道这个单向性,拿到 STL 想回去编辑,结果发现根本没法改。
2.3 为什么不做成"纯端到端大模型直接吐网格"
有人会问:现在生成式模型这么强,为什么不直接训练一个模型,输入文字输出网格,一步到位?我实际踩过这个坑。纯端到端生成网格,最大的问题是不可控。你让它生成一个带孔的板,它可能给你生成一个孔的位置偏了 2mm、或者孔根本不贯穿的模型。对于展示用途勉强能看,但对于任何需要精度和可制造性的场景,这就是废品。
参数化中间层的价值就在这里:每一步都有明确的数值,孔位是 (10, 10),直径是 6,这些数字可以被校验、被修改、被追溯。生成完之后你可以写规则去检查"壁厚是否小于 1mm""孔是否超出边界",不满足就报错或者自动调整。这种可控性,是纯端到端方案目前给不了的。所以我的判断是:短期内,参数化中间层 + 几何内核的组合,仍然是 text-to-cad 最靠谱的工程路线。
3. 核心细节解析:文本解析、几何生成与格式转换的关键环节
3.1 文本解析:怎么把"人话"变成"机器能懂的参数"
文本解析这一步,决定了整个系统的上限。解析得准,后面就顺;解析得糊,后面全是坑。我把它拆成三个子任务:实体识别、尺寸抽取、关系推理。
实体识别是找出描述里有哪些几何元素。比如"底板""圆柱""孔""倒角""筋板",这些词对应不同的特征类型。尺寸抽取是把"100mm""直径6""距边缘10mm"这些数值和单位抓出来,并且知道每个数值属于哪个实体。关系推理最难,它要理解"四角各有一个孔"意味着四个孔的位置是对称分布的,"孔中心距边缘10mm"意味着孔位和边界之间有约束关系。
实际做的时候,我建议用"规则 + 模型"的混合方案。纯规则能覆盖 70% 的常见表达,比如"长宽高""直径""阵列"这些高频词,用正则和词典就能搞定,又快又稳。剩下 30% 的复杂、口语化表达,交给语言模型去兜底。为什么不全用模型?因为模型有幻觉,它可能把"直径6"理解成"半径6",这种错误在几何上就是灾难。规则部分负责精确,模型部分负责灵活,两者互补。
注意:单位处理是个高频翻车点。用户说"100"的时候,到底是 100mm 还是 100cm?我的做法是默认毫米(工程界惯例),但在解析结果里显式标注单位,并且在最终生成前做一次单位归一化。曾经有个项目因为没做这步,用户输入"10"被当成 10 米,生成了一个 10 米长的零件,直接笑不出来。
3.2 几何生成:参数化描述如何驱动内核建模
拿到结构化参数之后,就进入几何生成阶段。这一步通常依赖一个成熟的几何内核,比如 OpenCASCADE(开源)、Parasolid(商业)这类。内核提供的是底层能力:创建长方体、创建圆柱、做布尔运算、倒角、抽壳。你要做的是把这些底层调用,按照参数化描述的顺序编排起来。
编排顺序很讲究。正确的顺序一般是:先建基础体,再做减材特征(打孔、挖槽),最后做修饰特征(倒角、圆角)。为什么?因为如果你先倒角再打孔,孔可能会把倒角切掉一部分,导致结果和你预期不符。这个顺序逻辑,和人工建模时的习惯是一致的——有经验的工程师也是先做大形,再做细节。
举个具体的参数计算例子。假设要生成一个带四个角孔的底板,孔中心距边缘 10mm,板尺寸 100×60。那么四个孔的圆心坐标分别是:
- (10, 10)
- (90, 10)
- (10, 50)
- (90, 50)
这个计算看着简单,但如果板尺寸是变量,孔距边缘也是变量,你就得写成(margin, margin)、(length - margin, margin)这样的表达式,让系统在运行时求值。我见过有人把坐标写死,结果用户一改板尺寸,孔就跑到板外面去了。所有位置参数都应该用相对表达式,而不是绝对数值,这是参数化建模的铁律。
3.3 格式转换:STEP 到 STL 的网格化参数怎么定
生成 STEP 之后,要转成 STL 或 GLB,中间要做网格化(tessellation)。这一步有个关键参数:弦高偏差(chordal deviation)和角度偏差(angular deviation)。简单说,就是用多少三角面片去逼近一个曲面。参数越小,面片越多,模型越精细,但文件越大、处理越慢。
我的经验值是这样的:做 3D 打印预览,弦高偏差设 0.1mm 左右就够了,肉眼基本看不出棱角;做网页展示,可以放宽到 0.2~0.3mm,文件小加载快;做精密分析或者大曲率曲面(比如球面、圆柱面),要压到 0.05mm 以下。这个参数没有绝对标准,取决于你的用途和对文件大小的容忍度。
提示:STL 文件本身不记录单位。很多切片软件默认按毫米处理,但如果你生成的 STL 实际是英寸单位,打印出来尺寸会差 25.4 倍。所以转换时一定要确认单位一致,最好在文件名或者元数据里标注清楚。
4. 实操过程:从零搭一条 text-to-cad 的最小可用链路
4.1 环境准备与依赖选型
要跑通一条最小链路,你需要三样东西:一个几何内核、一个语言解析模块、一个格式转换工具。我推荐的技术栈是 Python + CadQuery(基于 OpenCASCADE 的 Python 封装)+ 一个语言模型 API + trimesh(做网格转换)。
为什么选 CadQuery?因为它把 OpenCASCADE 那套复杂的 C++ 接口封装成了很 Pythonic 的链式调用,写起来直观。比如建一个带孔的板,代码大概长这样:
import cadquery as cq result = ( cq.Workplane("XY") .box(100, 60, 20) .faces(">Z") .workplane() .rect(80, 40, forConstruction=True) .vertices() .hole(6) ) cq.exporters.export(result, "plate.step")这段代码做的事情就是:建一个 100×60×20 的盒子,在顶面建工作平面,画一个 80×40 的构造矩形,在它的四个顶点打直径 6 的通孔,最后导出 STEP。你看,参数化描述里的"四角各有一个孔",在这里就是"构造矩形的四个顶点"。
4.2 完整流程的代码骨架
把语言解析接进来,整个流程分成四步:接收文本、解析成参数、驱动 CadQuery 建模、导出多格式。下面是一个可运行的骨架:
import cadquery as cq import trimesh import json def parse_text_to_params(text): # 这里接语言模型或规则解析,返回结构化参数 # 示例:解析"100x60x20的板,四角打直径6的孔,孔距边10" params = { "length": 100.0, "width": 60.0, "height": 20.0, "hole_dia": 6.0, "margin": 10.0, "unit": "mm" } return params def build_model(params): L, W, H = params["length"], params["width"], params["height"] d, m = params["hole_dia"], params["margin"] inner_L = L - 2 * m inner_W = W - 2 * m model = ( cq.Workplane("XY") .box(L, W, H) .faces(">Z") .workplane() .rect(inner_L, inner_W, forConstruction=True) .vertices() .hole(d) ) return model def export_all(model, base_name): cq.exporters.export(model, f"{base_name}.step") # 转 STL cq.exporters.export(model, f"{base_name}.stl", tolerance=0.1, angularTolerance=0.1) # 转 GLB mesh = trimesh.load(f"{base_name}.stl") mesh.export(f"{base_name}.glb") if __name__ == "__main__": text = "100x60x20的板,四角打直径6的孔,孔距边10" params = parse_text_to_params(text) model = build_model(params) export_all(model, "output_part") print("生成完成:output_part.step / .stl / .glb")这段代码跑通之后,你就有了一个能用的最小系统。输入一句话,输出三种格式的文件。当然,真实场景里解析部分要复杂得多,但骨架就是这个骨架。
4.3 参数校验:生成前必须过的几道关
模型生成之前,一定要做参数校验,否则很容易生成几何上非法的东西。我总结了几个必查项:
- 尺寸正负:长宽高、直径、壁厚必须为正数。负数尺寸会让内核直接报错或者生成诡异形状。
- 孔位越界:孔中心到边缘的距离,必须大于孔半径,否则孔会切穿边界。比如孔距边 10mm、孔半径 3mm,是安全的;但如果孔距边 2mm、孔半径 3mm,孔就出界了。
- 壁厚下限:如果模型有抽壳或者薄壁结构,壁厚不能小于某个阈值(比如 0.5mm),否则制造不出来。
- 特征干涉:多个特征之间不能互相冲突,比如两个孔重叠、倒角半径大于相邻面尺寸等。
这些校验用简单的 if 判断就能实现,但能挡掉大量低级错误。我的做法是:校验不通过就返回明确的错误信息,告诉用户哪个参数有问题、应该怎么改,而不是默默生成一个坏模型。
提示:校验逻辑最好和建模逻辑分开写,做成独立的校验函数。这样你可以在不建模的情况下快速验证参数,节省计算资源,也方便单元测试。
5. 常见问题与排查技巧实录
5.1 生成失败或模型为空怎么办
这是最常见的问题,表现是程序不报错,但导出的文件是空的,或者只有几个面片。排查思路按这个顺序走:
第一,检查参数是否合法。很多时候是某个尺寸为 0 或者负数,导致布尔运算结果为空。打印出解析后的参数字典,肉眼过一遍。
第二,检查布尔运算顺序。如果你先做了减材再做大形,减掉的部分可能被后面的操作覆盖了。确认顺序是"先加后减"。
第三,检查工作平面。CadQuery 里.workplane()的朝向很关键,如果工作平面方向不对,孔可能打在模型外面。用.faces(">Z")明确指定顶面,比默认行为可靠。
第四,检查内核报错。OpenCASCADE 有时候会吞掉异常,建议在关键步骤加日志,把每一步的中间结果导出看看。
5.2 格式转换后模型变形或丢失细节
这个问题通常出在网格化参数上。如果 STL 看起来棱角分明、曲面变成多边形,说明弦高偏差设太大了,调小到 0.05~0.1mm 试试。如果 GLB 打开后颜色或材质丢失,那是转换时没带上材质信息,需要在导出 GLB 时显式指定。
还有一种情况是模型"看起来对但尺寸不对"。这基本是单位问题。STEP 是有单位的,STL 没有。转换时如果没做单位换算,就会出现 25.4 倍的偏差。我的做法是在整个流程里统一用毫米,导出 STL 前再确认一次。
5.3 常见问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 模型为空 | 参数非法/布尔运算顺序错 | 打印参数、检查建模顺序 |
| 孔位偏移 | 用了绝对坐标而非相对表达式 | 检查坐标计算逻辑 |
| STL 曲面有棱角 | 弦高偏差过大 | 调小 tolerance 到 0.1 以下 |
| 尺寸差 25.4 倍 | 单位不一致 | 统一为毫米,转换前确认 |
| GLB 无材质 | 导出未带材质 | 导出时指定材质参数 |
| 生成速度慢 | 网格过密/模型过复杂 | 放宽网格参数,简化特征 |
5.4 几个我踩过的坑
第一个坑:过度信任语言模型。早期我全用模型解析,结果它把"半径3"和"直径3"搞混,生成的孔小了一半。后来改成规则优先、模型兜底,准确率立马上来了。
第二个坑:忽略浮点精度。两个本该重合的面,因为浮点误差差了 0.0001mm,布尔运算就失败了。解决办法是在关键运算前做一次坐标对齐,或者给内核设置合理的容差。
第三个坑:没做增量导出。一开始每次生成都覆盖旧文件,结果调试时想对比前后版本都做不到。后来改成带时间戳的文件名,问题一目了然。
6. 这套东西还能怎么扩展
跑通最小链路之后,我实际用下来觉得最有价值的扩展方向有三个。
第一个是模板库。把常见的零件类型(法兰、支架、齿轮坯、外壳)做成参数化模板,用户只需要填几个关键尺寸,不用每次从零描述。这比纯文本生成稳定得多,因为模板本身已经验证过几何合法性。
第二个是批量生成。热词里有个"python批量对cad修改",其实和 text-to-cad 是绝配。你可以读一张 Excel 表,每行是一组参数,批量生成几十上百个变体模型,用于系列化设计或者参数扫描。这个场景下 text-to-cad 的效率优势特别明显。
第三个是和下游工具打通。生成的 STEP 可以直接喂给 CAM 软件做加工路径,STL 可以直接进切片软件。如果能把这条链路自动化,从一句话到可打印文件,中间不需要人工干预,那才是真正把价值释放出来。
我个人在实际操作中的体会是:text-to-cad 现在最成熟的用法,不是替代设计师,而是把"重复性的、有明确参数的"建模工作自动化掉。你越能把需求描述得结构化、参数化,它生成的结果就越靠谱。反过来,如果你的需求本身就很模糊、很依赖审美判断,那还是老老实实手工建模更靠谱。工具是死的,怎么用是活的,找到它擅长的边界,比盲目追求"全自动"要实在得多。