跳转到内容

面向 AI 原生 3D 建模应用的 SDF、网格与 CAD 内核调研:模型、引用、事务与多内核

主文档与完整目录。本分篇保留原调查日期的依据与实测记录;其中的当前状态、建议和授权仅属于历史快照,不是执行队列。

6. 建议自研:Aira Modeling Intermediate Representation(AMIR)

Section titled “6. 建议自研:Aira Modeling Intermediate Representation(AMIR)”

AMIR 应是唯一规范模型,表层代码、GUI、AI prompt、插件 API 都只是它的视图或编辑入口。

必须具备:

  1. 纯数据、无任意代码执行。 模型不能带网络、文件、系统调用,也不能无限循环。
  2. 强类型的几何域。 Sketch2D、Profile2D、ExactSolid、MeshSolid、Field3D、Assembly、DisplayMesh 不可混用。
  3. 单位进入类型。 Length、Angle、Area、Volume、Ratio 分离;单位转换显式且可审计。
  4. 稳定 ID 独立于文本顺序。 node map 以 ID 为键,重排或格式化不改变身份。
  5. 依赖 DAG 和受限高阶构造。 循环用 bounded pattern/map/reduce 表示,可静态估算成本。
  6. 每个节点声明权威表示、精度与容差。
  7. 所有随机性有 seed;所有环境选择有版本。
  8. 输入、产物、诊断和三角形都可回溯到源节点。
{
"schema": "aira.model/v0.1",
"documentId": "doc.bracket",
"units": { "length": "mm", "angle": "deg" },
"tolerance": "0.001 mm",
"parameters": {
"width": { "type": "Length", "value": "80 mm", "range": ["20 mm", "200 mm"] },
"depth": { "type": "Length", "value": "40 mm", "range": ["10 mm", "120 mm"] },
"thickness": { "type": "Length", "value": "4 mm", "range": ["1 mm", "12 mm"] }
},
"nodes": {
"sketch.base": {
"op": "sketch.rectangle",
"target": "Sketch2D",
"plane": "XY",
"center": ["0 mm", "0 mm"],
"size": [{ "param": "width" }, { "param": "depth" }],
"outputs": { "profile": "outer_profile" }
},
"solid.plate": {
"op": "brep.extrude",
"target": "ExactSolid",
"inputs": { "profile": "sketch.base#outer_profile" },
"distance": { "param": "thickness" },
"outputs": {
"body": "plate",
"faces": { "start": "bottom", "end": "top", "sides": "walls" }
}
}
},
"assertions": [
{ "op": "isValidSolid", "input": "solid.plate#plate" },
{ "op": "minThickness", "input": "solid.plate#plate", "gte": "3.9 mm" }
]
}

这份 JSON 不是建议用户每天手写的最终语法,而是所有工具共享、可版本迁移、可自动验证的 canonical form。

建议做一个很薄的、纯函数式、pipeline 风格 .aira 语言:

model mounting_bracket units mm tolerance 0.001mm
param width: Length = 80mm in 20mm..200mm
param depth: Length = 40mm in 10mm..120mm
param thickness: Length = 4mm in 1mm..12mm
sketch @base on XY {
rectangle @outer center [0mm, 0mm] size [width, depth]
}
solid @plate: ExactSolid =
extrude profile @base.outer distance thickness
assert valid(@plate)
assert minThickness(@plate) >= 3.9mm

关键不是具体关键字,而是:

  • 表层语法与 AST 一一可逆;
  • formatter 产生唯一规范格式;
  • 任何 GUI 操作都能生成小而稳定的 AST patch,再同步回文本;
  • 高级用户可使用自动生成的 TypeScript builder SDK,但 SDK 只生成 AMIR,不能直接操作内核。

实现上建议解析为 lossless CST,再投影到以永久 node ID 为身份的语义 AST;注释、空白和其他文本 trivia 挂到 node ID,printer 只重写受 patch 影响的源码范围。这样既保留 Git 友好文本,也避免 AI 每次改一个参数却重写整份文件。

6.4 为什么不直接选 TypeScript 或 Python 当模型语言

Section titled “6.4 为什么不直接选 TypeScript 或 Python 当模型语言”

它们对 LLM 熟悉,但作为唯一 source of truth 有明显代价:

  • 任意控制流和副作用让增量重算、沙箱与成本估计困难;
  • AST diff 往往退化为脆弱的文本重写;
  • 单位、几何类型与表示精度只能靠约定;
  • 同一结果可有太多写法,降低训练和评测的一致性;
  • 很难保证 GUI 修改后仍生成优雅、可读、可维护的源码;
  • 错误栈混合宿主语言、绑定层和几何内核,AI 很难恢复。

因此最优组合不是“不要 TypeScript”,而是:

  • TypeScript:应用、插件 SDK、自动化 builder;
  • Rust:语言/IR/事务与本地服务;
  • C++/WASM:OCCT 与 Manifold;
  • AMIR/.aira:AI、人类与 GUI 共同理解的建模语义。
  • face[7]、edge[12];
  • “取面积最大的面”后默认选第一个;
  • 只保存一次运行中的 OCCT pointer/hash;
  • 从 Three.js triangle index 反推长期 CAD 身份;
  • 重算歧义时静默换到另一条边。

一个引用应同时包含:

  1. 来源: 哪个 feature、哪个命名输出产生;
  2. 角色: startCap、endCap、sideFrom(sketch.lineA)、filletSurface 等;
  3. 谱系: 经过哪些 Modified / Generated 历史;
  4. 几何约束: 类型、方向、解析曲面种类、半径/面积区间、邻接关系;
  5. 基数契约: expect exactly one / N / non-empty;
  6. 失败策略: 报告 missing、ambiguous 或 changed-kind,不自动猜。

示例:

{
"nodeId": "feature.fillet_outer",
"selector": {
"scope": "solid.plate#plate",
"entity": "Edge",
"lineage": { "createdBy": "solid.plate", "fromRole": "walls" },
"where": {
"convex": true,
"parallelTo": "Z",
"adjacentSurfaceTypes": ["Plane", "Plane"]
},
"expect": { "count": 4 }
}
}

执行顺序应是:

  1. 优先使用 feature output 与 OCCT/Manifold 历史映射;
  2. 再用结构/邻接关系;
  3. 最后才用几何 predicate;
  4. 结果不满足 expect 就终止事务并返回候选,而不是选择第一个。

每次内核执行都生成 ArtifactGraph,记录 feature 产物之间的 generated / modified / split / merged / deleted 谱系;在此基础上维护四向映射:

源代码范围 ⇄ AMIR node/port ⇄ kernel artifact/subshape ⇄ render primitive/triangle

由此才能实现:

  • 点场景中的面,定位到定义它的代码;
  • AI 查询某个 feature 实际产生了哪些面;
  • 诊断高亮到 3D 视口;
  • mesh boolean 后仍追踪材质与大致来源;
  • screenshot segmentation 使用稳定 artifact ID,而不是颜色猜测。

AI 不应拿到“运行任意源码”或一千个 OCCT 方法。推荐一个小型、自描述、可查询的领域工具面:

工具 作用
catalog.search 按能力、输入输出类型、精度、成本、失败模式检索操作
model.read 获取参数、特征图、选区、版本与摘要
model.query 几何/拓扑/测量/来源查询
model.proposePatch 对指定 baseRevision 生成领域补丁,静态检查但不提交
model.preview 在 quality budget 内执行候选图并返回 diff、诊断、图片/分割
model.validate 运行 exact/mesh/field/制造约束验证
model.commit 原子提交已验证补丁
model.revert 按 revision 回退
model.export 显式选择 STEP、3MF、GLB 等,并报告有损项

一个 patch 需要:

{
"baseRevision": "sha256:...",
"intent": "把四条外侧竖边做 3 mm 圆角",
"operations": [
{
"op": "insertNode",
"nodeId": "feature.outer_fillet",
"after": "solid.plate",
"value": {
"op": "brep.fillet",
"input": "solid.plate#plate",
"edges": { "ref": "selection.outer_vertical_edges" },
"radius": "3 mm"
}
}
],
"preconditions": [
{ "op": "revisionEquals", "value": "sha256:..." },
{ "op": "selectionCount", "ref": "selection.outer_vertical_edges", "equals": 4 }
]
}

事务语义:

  • preview 与 commit 使用相同输入、内核版本、容差和 seed;
  • commit 前必须重验 preconditions;
  • 失败不产生半修改状态;
  • 每次提交保存 prompt/intent、patch、前后 revision、诊断和产物摘要;
  • 相同 idempotency key 不得重复应用。

9. Geometry Observatory:让 AI 真正“看懂”模型

Section titled “9. Geometry Observatory:让 AI 真正“看懂”模型”

只给截图不够,只给 B-Rep dump 也不够。每次执行建议返回:

  • 参数与表达式求值;
  • 节点状态:clean / dirty / running / failed / approximated;
  • 产物类型与权威表示;
  • bounding box、体积、面积、重心、惯量;
  • body/face/edge/vertex 数与拓扑摘要;
  • surface/curve 类型分布;
  • manifold、自相交、空壳、负体积、退化元素;
  • 约束自由度、冲突集合、冗余约束;
  • selected refs 的解析过程与候选;
  • 有损转换记录和误差界;
  • 正交六视图、透视图、深度、法线、feature-ID segmentation;
  • 执行耗时、峰值内存、三角形数与缓存命中。

这些结果应收敛成可持久化的 Geometry Certificate:记录 exact / approximate / voxelized 等表示等级、kernel 名称与精确版本、input hash、单位/tolerance、采样分辨率、watertight/manifold/self-intersection 状态、来源保留程度、警告与可执行修复建议。它不是“绝对正确证明”,而是让 AI、回归系统和导出流程知道这次结果究竟保证了什么。

错误必须是稳定 code + 结构化 payload:

{
"id": "diag:01K3EXAMPLE00000000000000",
"code": "FILLET_RADIUS_TOO_LARGE",
"severity": "error",
"phase": "kernel",
"at": { "nodeId": "feature.outer_fillet", "port": "radius" },
"messageKey": "geometry.fillet.radiusTooLarge",
"details": {
"entities": ["edge.outer.0", "edge.outer.1"],
"requested": { "value": "12", "unit": "mm" },
"safeUpperBoundEstimate": { "value": "4.82", "unit": "mm" }
},
"fixes": [
{
"kind": "patchTemplate",
"action": "reduceRadius",
"suggested": { "const": { "type": "Length", "value": "4.5", "unit": "mm" } }
},
{
"kind": "patchTemplate",
"action": "excludeEntity",
"entity": "edge.outer.1"
}
]
}

这比异常字符串更能帮助 AI 自我修复,也更容易做自动评测。

操作 默认后端 权威输出
约束草图、精确 extrude/revolve/loft/sweep OCCT ExactSolid
fillet/chamfer/shell/draft、STEP import/export OCCT ExactSolid
manifold mesh import、mesh boolean、split、打印修整 Manifold MeshSolid
smooth union、lattice、warp、gyroid Field compiler Field3D
Field 烘焙 Manifold LevelSet(首版) MeshSolid,带误差
视口三角化 OCCT tessellator 或 Manifold MeshGL DisplayMesh
材质、相机、辅助线、选择高亮 Three.js SceneView

允许:

  • ExactSolid -> DisplayMesh:tessellate,派生、可重建;
  • ExactSolid -> MeshSolid:显式 bake,记录 chordal/angular deflection;
  • Field3D -> MeshSolid:显式 bake,记录 bounds/edgeLength/tolerance;
  • MeshSolid -> Field3D:显式 voxelize/distance,记录分辨率与 sign 方法。

默认禁止:

  • MeshSolid -> ExactSolid 的“自动精确化”;
  • Field3D -> ExactSolid 的泛化转换;
  • 把导入 STL 当成可无损编辑的 CAD;
  • 由 Three.js BufferGeometry 反写设计历史。

同一 feature graph 可以包含多种权威实体,但每个 part/body 的当前权威表示必须唯一。

约束对“AI 原生 CAD”不是可选项。ICLR 2022 的 Vitruvion 把参数化草图明确描述为“约束程序”,指出设计意图不仅在几何 primitive 中,也在元素之间的参数关系中。论文

可选路线:

  • FreeCAD PlaneGCS 是成熟的 LGPL-2.1-or-later 2D 几何约束求解器。
  • planegcs WASM wrapper 提供 TypeScript annotations,并支持 DogLeg、Levenberg-Marquardt、BFGS、SQP 等路径;README 也坦承某些 non-driving 约束和组合仍有使用陷阱。
  • SolveSpace 的 libslvs 能力成熟,但 GPLv3 会显著影响闭源集成方式。
  • 商业路线可评估 Siemens D-Cubed 2D DCM,但不适合作为开源 MVP 的默认依赖。

建议:

  1. AMIR 先定义自己的 SketchEntity / Constraint / DOF / ConflictSet,不绑定任何 solver 数据结构。
  2. 首版对 planegcs WASM 做独立验证,特别测试拖拽、过约束、冗余、初值敏感和大尺度差异。
  3. 把 solver 的 raw residual、自由度与冲突候选转成稳定诊断。
  4. 如果闭源分发、体积或行为稳定性不满足需求,再评估自研窄而可解释的 solver;不要一开始重写全部 CAD 约束算法。