AI辅助CAD建模:几何内核与OpenGL渲染协同的实现路径

📅 发布时间:2026/10/20 22:04:41
AI辅助CAD建模:几何内核与OpenGL渲染协同的实现路径
这几年AI在CAD领域的热度大家都看到了。客户一上来就问能不能让软件听懂人话我说“给支架加个圆角”它就把圆角加上。理想很丰满但真正把这功能落地的时候会发现一个尴尬的事实大模型能听懂人话但它压根不知道“支架”长什么样。它在哪里它有几条边加圆角会不会把旁边的孔搞穿这些信息不在训练数据里而藏在当前这个三维模型的几何内核里。换句话说你给CAD装上了AI大脑但还差一双能看懂模型的“几何慧眼”。这篇算是OpenGL渲染与几何内核那点事的第二篇项目实践补充分支专门聊AI作为“司机”和几何内核作为“眼睛”的协作关系。如果你正打算给自己的CAD软件接大模型或者负责AI辅助建模模块希望这些经验能让你少走弯路。1. 先搞明白AI大脑和几何内核谁说了算1.1 “司机”的比喻大脑负责决策眼睛负责感知把AI当成司机是挺贴切的一个司机坐在驾驶位上知道接下来要往哪开、打多少方向盘这是决策但他必须先看到路况、判断距离、看后视镜这是感知。没有感知的决策全是盲开。放到CAD里AI模型就是那个大脑它给出“把这条边倒圆角、半径2毫米”的决策但真正执行之前它得先知道这条边到底存不存在、和哪些面相邻、当前有没有被其他特征挡住。这些感知信息AI自己是编不出来的必须由几何内核实时提供。我在实际项目里见过太多类似的方案团队费了好大劲把大模型接进来提示词写得花团锦簇结果一测试就发现AI给出的面ID根本不对或者要倒角的边压根不是用户指的那一条。问题不在AI推理而在感知层没打通。大脑再聪明眼睛没睁开之前车是不敢动的。1.2 为什么底层数据结构决定了AI“看得见”还是“看不见”CAD模型在计算机里有两种完全不同的表示方式。一种是我们日常在屏幕上看到的三角网格它由成千上万个三角形组成适合显示但精度很粗糙另一种是几何内核维护的精确数学模型比如一个圆柱面存的是它的轴向量、半径、高度这些精确参数而不是一堆近似三角形。大模型在训练时见过的“CAD图片”大多是网格渲染出来的它生成的自然语言命令本质上还是一串符号。要让这串符号落在准确的三维实体上就必须和精确模型打交道。几何内核的意义就在这里它把“哪个点是哪个顶点、哪条边属于哪个面、哪个面围成哪个体”这些拓扑关系完整保存下来。AI通过查询接口才能从模糊的图像认知切换到精确的数学认知。这一步没做AI生成的命令就有很大的概率是“好看但不可执行”。我们在第一次集成测试时就遇到过AI自信地输出“对面F21做拉伸”但F21其实是模型里一条辅助线的端点编号压根不是一个面。原因就是AI只是在文本里猜了一个ID根本没有查内核。1.3 渲染不是配角它是AI和用户之间的“神经反馈”很多人觉得OpenGL渲染只是把模型显示出来跟AI辅助建模关系不大。这话放在传统CAD里勉强成立但是AI一进来渲染的地位立刻变了。第一个理由是拾取用户说“选这个面”本质上是一个屏幕坐标要把它换算成内核里的面ID必须经过OpenGL的投影反变换和射线求交。第二个理由是反馈AI说要倒角用户得在屏幕上看到高亮的那条边到底选没选对这个可视化反馈循环是建立信任的基础。第三个理由是状态可视化给AI加几何查询的时候可以把查到的面法向、边方向、曲率信息直接渲染出来方便调试。所以我们内部做AI辅助模块时渲染组和内核组坐在一起开发一点也不奇怪。OpenGL渲染和几何内核一个是看得见的表象一个是算得动的本质AI大脑夹在中间两头都得通。2. 几何内核的“几何慧眼”能看见哪些东西2.1 从拓扑到几何把一张网和一套坐标系拼起来几何内核的“眼睛”第一层是B-rep数据结构。B-rep的全称是边界表示核心思想是一个三维实体不用靠体素填充来描述而用它的边界来定义。边界又分两层拓扑层和几何层。拓扑层描述的是连接关系比如一个长方体有6个面、12条边、8个顶点几何层描述的是每个元素的精确形状比如某个面是平面、法向朝上某条边是直线段某个顶点在坐标原点。拓扑实体负责描述什么对应几何数据举个例子Vertex点的存在性Point三维坐标角点Edge边的连接性和边界Curve直线、圆弧、样条一条棱Face面的边界和方向Surface平面、圆柱面、NURBS顶面Shell闭合面片的集合无要求曲面连续一个壳Solid闭合壳体围成的三维区域无整个零件拓扑和几何必须一一对应但又彼此独立。这个设计很关键同一个拓扑顶点几何位置可能因为容差有微小偏移同一条拓扑边可以被多个面共享。AI要操作模型首先得确定这个对应关系。比如用户说“给底面倒角”AI查到某个Face的几何曲面是平面法向朝下这个面就是底面。如果拓扑层说这个面是一个Loop包出来的但几何层却查不到这个Loop的Curve数据那基本上就是内核数据已经坏了。实际开发里我们写了不少断言函数来处理这类问题。2.2 AI最常用的三类查询遍历、属性、谓词第一类是拓扑遍历类给定一个Face找出它周边的所有Edge给定一条Edge找出左右两个Face给定一个Solid列出所有外壳。这些查询相当于人的“扫一眼”AI用来构建模型局部结构。第二类是几何属性类算Edge的长度、Face的面积、Solid的体积、某点的法向量、某条曲线在某处的曲率半径。这些数据可以帮助AI判断一个操作是否合理。第三类是状态谓词类两个面是不是共面、两条边是不是平行、两个圆柱面是否相切、某个点是不是在某个面内。这类查询是AI“能不能这么干”的关键依据。以倒圆角为例AI先找到目标边这条边两侧的面必须满足最小角度约束否则倒出来的圆角可能和旁边的面自相交。这些判断用谓词接口几分钟就能查出来如果靠AI猜基本必错。我记得一次测试里AI想对一个窄条的短边倒R2的圆角从文本上完全看不出问题但内核一查那条边长度只有1.8毫米R2根本放不下。正是靠长度查询AI才在真正建模前拦截了这个错误。2.3 B-rep为什么天然适合AI感知我琢磨过很久为什么B-rep这种几十年前就定下来的数据结构到今天依然适合做AI的视觉层。答案是它把“模糊的三维实体”变成了“有限的、可枚举的零部件清单”。三维空间本身是连续无穷的但B-rep把一个实体描述成有限个面、有限条边、有限个点的集合并且明确记录了它们之间的邻接关系。对AI来说这意味着它不需要处理连续空间里的所有可能只需要在这个有限图结构上做推理。打个比方你要告诉AI整理房间不如给AI一张房间物品清单说清楚柜子有几扇门、门上有几个把手、把手和门怎么连接。B-rep就是这张清单。而且这张清单是可计算的能求面积、能算相交、能判断位置关系AI拿着它才能从“生成一段看起来合理的文本”变成“生成一个真正能落到实体上的建模操作”。3. OpenGL渲染从光栅化画面反推模型数据的技巧3.1 GPU不认识B-rep渲染前必须“摊开”成三角形前面说了B-rep是精确表示可OpenGL渲染管线只认顶点和三角形。所以从内核到渲染中间有一个必经步骤曲面离散化。一个圆柱面要被切成很多条细长的三角形一个球面也要按经纬方向细分。这个过程的专业叫法是“网格生成”或“曲面细分”。细分密度直接关系到显示质量太粗了圆弧看起来像多边形太细了顶点太多每帧开销变大。我们实际项目里通常用两级显示精度交互旋转时用较粗的网格停下来之后再细化或者按视角距离动态调整。这步如果做得不好AI高亮选中的边在屏幕上就会对不齐用户第一眼就感觉不对劲。网格生成不是内核的“额外负担”它是衔接几何计算和像素显示的必经桥梁。3.2 射线拾取把鼠标点变成内核里的一条边AI要操作模型自己得先有“点选”的能力。最简单的实现是射线拾取从相机位置出发穿过鼠标所在的屏幕像素形成一条射线然后与模型的所有三角形求交命中最近的三角形就能反查它属于哪个Face。这一步看起来简单要做稳需要处理好几个细节。屏幕坐标要先经过视口变换转成标准化设备坐标再乘逆投影矩阵和逆模型矩阵转回模型局部坐标系否则在旋转视图下拾取会偏。三角形求交要用重心坐标判断命中点是否落在三角形内部。命中之后还不能直接返回三角形因为一个大的Face可能被切成上千个三角形最终要顺着三角形反查它所属的内核Face ID。如果想让AI“指边”不能用三角形求交了得用射线到每条边的最短距离来判断小于一定像素阈值才认定选上。我们当时调试的时候发现钝角弯曲的边特别难选中后来加了一个额外的“边距离优先”的判断才解决。3.3 高亮和探测渲染出来的不仅是画面也是AI的思考过程还有一个很容易被忽略的用途把AI的思考过程可视化。比如AI从自然语言里猜出用户想选的是“顶面”它先在内核里查到候选面集合然后在界面上把这个面高亮成半透明绿色。用户一看就知道AI理解得对不对。同样AI计划要对某条边倒角可以先把这条边描成高亮线框。这种可视化反馈其实是在把几何内核的查询结果变成人可理解的信息。调试阶段这个手段更有价值我们曾经把从内核里查到的边方向向量绘制成箭头、把面的法向量绘制成线条叠在模型上一眼就能发现数据是否错位。换句话说OpenGL在这里不再是“画得好看”的渲染器而是成为AI和用户之间的共同语言。4. 实操记录在模拟项目X上打通“AI内核渲染”链路4.1 项目场景用户说“给支架顶面边缘加R2的圆角”我拿我们之前做的某跨平台CAD系统举例子。目标功能是用户在界面里指着模型说“给这个支架顶面边缘加R2的圆角”AI要能听懂并且正确执行。拆解下来至少包含4个模块语音/文本识别模块把话变成意图选区确认模块通过鼠标拾取确定目标面几何内核模块执行圆角重建渲染模块刷新显示。这四个模块单独拆开都有人会做难的是组合。尤其是AI要自己提取“顶面”这个词而程序里没有“顶面”这个概念只有一个个Face对象每个Face带着复杂的几何数据。这时候就需要AI根据几何查询结果自己判断哪个面的法向量接近朝上哪个面在给定方向上最高这类空间语义判断恰恰是几何内核查询接口的价值所在。4.2 模块间数据流分步看AI是怎么“看见”的第一步用户鼠标拾取屏幕上的某个点OpenGL渲染层返回一个候选Face ID集合。第二步AI接收到自然语言里的“顶面”发起一轮几何查询遍历这个Face的所有邻接面用“法向量点积向上”的阈值筛选出顶面。第三步AI再查这个顶面的外环Loop得到环形边界上的一组Edge。第四步AI向内核提交倒角参数同时先做预检查比如目标Edge的长度必须大于半径R的2倍相邻面的角度不能太小否则警告用户。第五步内核执行B-rep倒角操作返回新的Solid。第六步渲染层把新Solid重新离散化、重新上传显存、绘制画面。整个链路里AI只在语义层做决策而每一步数据和计算都由内核和渲染层背书。你看这不是“AI什么都会”而是AI学会了调用几何慧眼。4.3 关键的查询接口设计给AI一个“几何上下文获取器”实际开发里我们不会让AI直接去调底层的一堆API否则大模型会乱。我们做了一层薄薄的封装类似一个“几何上下文获取器”专门把内核查询变成AI友好的接口。接口大约长这样def get_model_context(face_id): 把内核里的拓扑邻接关系转成AI方便理解的字典 context {} context[face_normal] get_face_normal(face_id) context[face_area] get_face_area(face_id) context[adjacent_faces] get_adjacent_face_ids(face_id) context[outer_edges] get_outer_loop_edge_ids(face_id) edge_info [] for eid in context[outer_edges]: edge_info.append({ edge_id: eid, length: get_edge_length(eid), curvature: get_edge_curvature(eid), }) context[edge_list] edge_info return context这个经验很重要AI越是底层越容易出错。给AI提供的是“当前选中面对应的几何上下文”而不是让它猜测“顶面”应该怎么生成。我们在测试中发现只要接口定义得清晰大模型返回的目标参数就会稳定很多。反过来说如果接口模糊比如“返回一个含有所有面信息的列表”大模型在几十个面里挑错ID的概率会直线上升。4.4 渲染侧的配合VBO更新、拾取缓冲、交互反馈链路执行到第五步和第六步时渲染最要命。第一次做全量刷新的时候两千个小三角面全重建界面卡了快两秒。后来我们给模型加了“脏区域”标记AI只改了顶面附近的拓扑那就只重新生成受影响Face的三角形再用局部VBO子范围更新把耗时压到几十毫秒。拾取缓冲也单独做了优化用一张离屏FBO把每个Face画成唯一颜色鼠标点下去直接glReadPixels读颜色值反查Face ID比跑射线和三角形求交快得多。高亮反馈也要单独做一层普通模型用的是暖色光照高亮面用纯色半透明渲染边缘用线框描边避免和普通面混淆。设计这套交互时我最大的体会是渲染不能只充当“最后一步”它要在整个AI操作闭环里从头参与到尾。5. 避坑记录做“司机”时我踩过的几何渲染坑5.1 内核容差和AI“随口一说”的参数AI给出的参数经常不靠谱。典型例子是倒角半径用户说“来个贼小的圆角”AI解析出一个0.001mm的半径但在CAD建模里每个模型都有一个建模容差通常默认在1e-6到1e-3量级。如果特征尺寸小于容差的若干倍内核在执行布尔运算时会直接失败或者生成一个退化面。我们的对策是所有从AI来的几何参数在内核执行前必须过一遍“参数合理性检查”包括最小尺寸、最大尺寸、与相邻特征的距离。发现越界就不往下执行直接把原因反馈给用户。这一步看似是业务逻辑其实挽救了很多次“AI把我模型改坏了”的事故。5.2 拾取命中边界的“边缘问题”屏幕上的模型是由三角形组成的而我们要拾取的内核边是B-rep里的拓扑边两者不是一回事。一块大曲面被离散成几百个三角形后三角形之间的内部网格边会被误识别为“Edge”。如果直接用三角形求交来反查边经常捡到网格边而不是拓扑边。我们最后是在内核侧维护“三角片到拓扑Face/Edge的映射表”渲染侧只以拓扑Face为单位做颜色编码拾取要拾取拓扑边时不要从三角形求交而是单独做边距离判定的射线检测。这个坑让我明白渲染数据是“看”的内核数据是“算”的两者之间如果没有明确的映射关系AI很容易被表象骗了。5.3 全量重算渲染和拓扑重算的连锁爆炸当AI连续执行多个操作比如先拉伸、再抽壳、再倒角如果每次都在整个模型上做B-rep重建和全量网格离散化性能一定崩。我们的做法是轻量级“操作队列”AI在底层链路上只提交“意图参数”内核把每个操作转换为受影响的局部区域渲染层维护一个脏标记列表只有标记过的面才重新生成网格。保证到OpenGL侧每次draw call只更新一小块VBO。这套优化本质上和渲染无关但做不好渲染一定是最直观的受害者。5.4 坐标系和变换矩阵千万别写反有一次AI给出“把这条边向下移动5毫米”执行结果却是模型飞了。查了半天发现是渲染层和内核层用的坐标系不一样渲染层用了右手坐标系的视图变换内核层用的世界坐标而拾取返回的屏幕坐标DPI系数没有还原导致一个坐标经过两次变换后放大了好几倍。这个问题的排查过程特别折磨人。后来我们规定所有跨模块传递的坐标统一放在“模型局部坐标系毫米单位”渲染层只在最终上屏时才应用相机变换矩阵。这条约定救了我们很多次。做AI辅助建模这段时间我越来越觉得AI不可能靠生成命令就接管CAD它必须依赖一个真正理解几何的底层。OpenGL渲染和几何内核不是一个提供画面、一个提供算法那么简单它们是AI在三维世界里睁开眼睛的必要条件。如果你也在做类似的功能我建议先把几何查询和拾取反馈跑通再让大模型登场。眼睛没睁开司机再聪明也开不了车。这条链路越往后做你会越发现几何内核提供的不是一堆函数而是三维世界唯一可靠的坐标系。