☰
CADAM 参数化建模实战:用 OpenSCAD 生成可调参数的扭曲六棱花瓶(Twisted Hexagonal Vase)
2026/10/15 2:51:17 网站建设 项目流程
  • 人工智能
  • AI 应用
  • 前端
  • 3D渲染

【免费下载链接】CADAM

CADAM is the open source text-to-CAD web application

项目地址:https://gitcode.com/gh_mirrors/ca/CADAM
点击查看免费下载

本篇技术指南以 CADAM 开源仓库 benchmarks 目录下的 01-twisted-hex-vase.md 文档为骨架,完整拆解其对应的 01-twisted-hex-vase.scad 参数化源码:如何用一条自然语言提示词让 CADAM 生成"可调尺寸、可调颜色"的全参数化 OpenSCAD 花瓶,又如何用linear_extrude(twist=, scale=)实现"扭曲放样 + 空心壳 + 实心底"这一经典 CAD 造型套路。读完你既能直接复制运行这份模型,也能理解 CADAM 把"变量声明 + Customizer 注释"变成参数面板、再把参数回写进源码的完整闭环,并掌握用 render.sh 在本地复现同款环绕渲染 GIF 的方法。

一、先看结果:一份提示词,一个可调参数的花瓶

这个 benchmark 的起点是一条纯自然语言描述(原文 Prompt):

Design a twisted hexagonal vase: a hollow shell about 150 mm tall that tapers from a 70 mm base to a 50 mm mouth, with the hexagonal cross-section twisting 120 degrees from bottom to top, a 2 mm wall, and a closed bottom.

把它翻译成建模约束,就是:约 150 mm 高的空心壳、底部 70 mm → 顶部 50 mm 的收口锥度、六边形截面自下而上扭转 120°、壁厚 2 mm、底部封闭。CADAM 把这句话转换成了完全参数化的 OpenSCAD——尺寸和颜色都可调,可导出.SCAD,并通过 render.sh 渲染出环绕旋转预览(如 benchmarks/README.md 所述,也可导出.STL/.DXF)。

按 benchmarks/README.md 的分类,本案例属于Parametric fundamentals(参数化基本功)一档,标明的能力点是:generative twist-loft(生成式扭曲放样)、空心壳 + 实心底、以及壁厚在六边形面上的真实补偿,控制面数为6 个维度参数 · 1 个颜色参数。

二、几何构建原理:扭曲放样、空心壳与实心底

完整源码位于 benchmarks/01-twisted-hex-vase.scad,核心只用一个difference()+ 两个linear_extrude()就完成了全部造型,技巧相当凝练:

color(vase_color) difference() { // Outer Solid Shell linear_extrude(height = height, twist = twist_angle, scale = scale_out, slices = slices) circle(r = r_bot_out, $fn = 6); // Inner Cut (Hollow) // We intersect the twisted inner solid with a lifted cylinder // to leave a solid floor of exactly `wall_thickness`. intersection() { linear_extrude(height = H_in, twist = twist_in, scale = scale_in, slices = slices) circle(r = r_bot_in, $fn = 6); translate([0, 0, wall_thickness]) cylinder(h = H_in, r = max(base_radius, mouth_radius) * 2, $fn = 32); } }

逐层拆解它的三个关键设计:

1. 生成式扭曲放样(twist-loft)

外壳由circle(r = base_radius, $fn = 6)这个六边形截面经linear_extrude一次成型:twist = twist_angle让截面沿高度方向旋转 120°,scale = r_top_out / r_bot_out让截面按半径比值从底到顶均匀缩放,得到"锥形 + 扭转"的六棱体。$fn = 6把圆离散成 6 段,即正六边形(此时circle的半径是外接圆半径 circumradius,所以直径是半径的 2 倍——这正是文档参数表里对base_radius/mouth_radius的注释说明)。slices = height * 2决定扭曲放样在竖直方向切分的段数,数值越高扭转越平滑。

2. 空心化与实心底

内部挖空不能简单地"再放一个小一号的扭曲体然后差集",因为六边形在旋转过程中,内壁与外壁的相对位置会漂移。这里的做法是:先把内壁实体也做同样的扭曲放样(内径r_bot_in、twist_in、scale_in均按比例缩放),再用一个抬升了wall_thickness的圆柱与它做intersection():

  • translate([0, 0, wall_thickness])把圆柱抬到离底面wall_thickness的高度,切掉内壁实体的底部一段,从而保留恰好wall_thickness厚的实心底板;
  • 圆柱半径取max(base_radius, mouth_radius) * 2,保证其水平截面完全覆盖六边形任意半径位置的扭转截面,不会在角部漏挖。

3. 六边形平角补偿(壁厚保真)

六边形外接圆半径与内切圆半径之间存在cos(30)的关系:若直接让内壁半径等于外径 - wall_thickness,那么平边(flat)处的真实壁厚会被"削薄"。源码中的隐藏参数做了补偿:

wall_adj = wall_thickness / cos(30); r_bot_in = base_radius - wall_adj; r_top_in_at_H = mouth_radius - wall_adj;

这就是文档 "Compensates the hexagon flat-angle so the wall thickness stays true on every face" 所指的核心细节——对六边形而言,真正保证每个平面法线方向壁厚为 2 mm 的,是沿内切圆方向扣除wall_thickness / cos(30),而不是简单地按外接圆半径减 2。

三、可编辑参数:5 个尺寸 + 1 个颜色

原文档给出了完整的参数表(6 个维度参数·1 个颜色),逐项继承如下,并补充了每个参数的几何含义与 Customizer 范围语法:

参数默认值范围 / 选项说明
height150[50:5:300]花瓶总高度(mm)
base_radius35[20:1:100]底部半径(外接圆半径,直径为其 2 倍)
mouth_radius25[10:1:80]瓶口半径(外接圆半径,直径为其 2 倍)
twist_angle120[-720:5:720]自底到顶的总扭转角(度),可负向扭转
wall_thickness2.0[0.5:0.5:5.0]壁厚与底板厚度
vase_color"Turquoise"CSS 颜色名 /#RRGGBB花瓶颜色

范围语法[min:step:max]是 OpenSCAD Customizer 风格注释。在 CADAM 中,这些注释不是摆设——前端会直接从源码解析出参数元数据。见 shared/parseParameters.ts 的说明:模型只输出 OpenSCADcode,客户端据此派生出"哪些变量可以作为滑块/输入框",保证同一份源码无论由哪个模型生成,都渲染出相同的参数面板。解析规则要点:

  • 只解析文件顶部、第一个module或function关键字之前的变量声明(其后是内部实现,不作为 API 暴露);
  • name = 10; // [1:50]视为 min:max,// [1:1:50]视为 min:step:max,// [red, green, blue]视为枚举,裸数字注释视为字符串的 maxLength 或数值的 step(shared/parseParameters.ts);
  • 引用了其他变量或跨行的赋值表达式会被跳过——它们是由其他参数推导出的派生值,而非可编辑常量(shared/parseParameters.ts);
  • /* [Group Name] */分组注释会把后续变量归入对应分组(本案例的[Dimensions]、[Style]、[Hidden]三组)。

颜色参数的识别也很关键:isColorParameter会通过 canvasfillStyle归一化来判断字符串值是否为合法 CSS 颜色(src/utils/parameterUtils.ts),命中后参数面板会渲染成原生取色器,并把颜色参数单独收进可折叠的Colors分组(src/components/parameter/ParameterSection.tsx)。

四、完整源码精讲:可直接复制运行

下面这份是与文档完全一致的完整源码(源码文件见 benchmarks/01-twisted-hex-vase.scad),已含全部参数注释,可直接用 OpenSCAD ≥ 2021.01 打开并实时拖动参数:

// Twisted Hexagonal Vase /* [Dimensions] */ // Total height of the vase height = 150; // [50:5:300] // Base radius (circumradius, so diameter is 2x this) base_radius = 35; // [20:1:100] // Mouth radius (circumradius, so diameter is 2x this) mouth_radius = 25; // [10:1:80] // Total twist angle from bottom to top (degrees) twist_angle = 120; // [-720:5:720] // Thickness of the walls and base wall_thickness = 2.0; // [0.5:0.5:5.0] /* [Style] */ // Color of the vase vase_color = "Turquoise"; /* [Hidden] */ // Compensation for the hexagon's angle to maintain true wall thickness on the flats wall_adj = wall_thickness / cos(30); // Number of vertical slices for a smooth twist slices = height * 2; // Outer geometry variables r_bot_out = base_radius; r_top_out = mouth_radius; scale_out = r_top_out / r_bot_out; // Inner geometry variables r_bot_in = base_radius - wall_adj; r_top_in_at_H = mouth_radius - wall_adj; // Extend the inner cutter slightly to ensure a clean opening at the top cut_extra = 2; H_in = height + cut_extra; // Calculate slope of inner radius change to maintain perfect alignment slope = (r_top_in_at_H - r_bot_in) / height; r_top_in = r_bot_in + slope * H_in; scale_in = r_top_in / r_bot_in; twist_in = twist_angle * (H_in / height); color(vase_color) difference() { // Outer Solid Shell linear_extrude(height = height, twist = twist_angle, scale = scale_out, slices = slices) circle(r = r_bot_out, $fn = 6); // Inner Cut (Hollow) // We intersect the twisted inner solid with a lifted cylinder // to leave a solid floor of exactly `wall_thickness`. intersection() { linear_extrude(height = H_in, twist = twist_in, scale = scale_in, slices = slices) circle(r = r_bot_in, $fn = 6); translate([0, 0, wall_thickness]) cylinder(h = H_in, r = max(base_radius, mouth_radius) * 2, $fn = 32); } }

对[Hidden]段做几点易忽略的说明:

  • wall_adj = wall_thickness / cos(30):六边形平角补偿量,见第二节第 3 点;
  • slices = height * 2:纵向切片数。height = 150时即 300 段,保证 120° 扭转平滑;
  • cut_extra = 2与H_in = height + cut_extra:把内壁切割体略微加高 2 mm,确保瓶口处切穿、形成干净开口,同时按斜率slope推算顶部内径r_top_in,使内外两个锥形放样的缩放斜率严格对齐,避免内壁与外壁在顶部错位;
  • twist_in = twist_angle * (H_in / height):内壁切割体比外壁长,若沿用同一扭转角会在顶部多转一点,因此按H_in / height比例同步放大扭转角,保证内外壁在任意高度处的棱线对齐。

注意[Hidden]组下的变量是派生量,按 shared/parseParameters.ts 的规则不会被暴露为可编辑参数——这正是该分组命名 "Hidden" 的意义。

五、参数如何回流成新的模型:CADAM 的闭环机制

在 CADAM 应用内,拖动参数后整个链路是端到端的(这解释了为什么文档强调"fully parametric"):

  1. 回写源码:updateParameter(code, param)用正则定位变量名 = 值;并替换为新值,字符串类型会正确处理转义与引号(src/utils/parameterUtils.ts),随后以-Dname=value命令行参数形式传给 OpenSCAD(src/worker/openSCAD.ts);
  2. 前端编译:OpenSCAD 以 WASM 形式跑在浏览器 Worker 里(src/worker/openSCAD.ts),编译时启用--backend=manifold、--enable=lazy-union等标志,并同时输出/out.stl与携带逐面color()信息的/out.off,供彩色预览解析(src/worker/openSCAD.ts);
  3. 库自动挂载:Worker 会先剥离字符串与注释,再用include <BOSL2/...>/use <BOSL2/...>语句正则匹配来按需加载 BOSL2、BOSL、MCAD 库(src/worker/openSCAD.ts),库 zip 即仓库 public/libraries 下的三个文件(清单见 src/lib/libraries.ts);
  4. 导出:参数面板提供.STL(3D 打印)、.SCAD(OpenSCAD 源码)、.DXF(向 x-y 平面的 2D 投影)三种下载,其中 DXF 在点击时才现场重新编译(src/components/parameter/ParameterSection.tsx)。

值得一提的是,CADAM 对生成代码的约束(src/server/aiChat.ts)恰好与本例的写法一一对应:所有可编辑参数声明在文件顶部、使用完整 snake_case 命名、每个变量后跟 Customizer 范围注释、可选的上一行// 描述注释、/* [Group] */分组、颜色参数命名为*_color且默认值为 CSS 命名色或#RRGGBB——这份花瓶 .scad 可以说是这套规范的教科书式范本。

六、本地复现:用 render.sh 渲染环绕 GIF

文档中提到的render.sh用于把任意.scad渲染成干净的环绕 GIF(以及可选的 4 视图拼贴 sheet),它镜像了 CADAM 浏览器端预览的行为:库路径上挂载 BOSL2、保留color()部件、绕竖直轴环绕。前置依赖与用法(macOS 示例,任何支持 BOSL2 的 OpenSCAD ≥ 2021.01 均可):

# OpenSCAD CLI + ImageMagick brew install --cask openscad@snapshot brew install imagemagick # BOSL2(和 BOSL)放到 OpenSCAD 库路径上——仓库已内置 zip mkdir -p /tmp/oscad-libs/BOSL2 /tmp/oscad-libs/BOSL unzip -o ../public/libraries/BOSL2.zip -d /tmp/oscad-libs/BOSL2 unzip -o ../public/libraries/BOSL.zip -d /tmp/oscad-libs/BOSL

随后:

./render.sh 01-twisted-hex-vase.scad # -> 01-twisted-hex-vase.gif(环绕动画) ./render.sh --sheet 01-twisted-hex-vase.scad # -> 01-twisted-hex-vase.sheet.png(iso/前/右/顶 4 视图)

脚本还暴露了若干环境变量旋钮(benchmarks/render.sh),默认值与作用如下:

环境变量默认值作用
FRAMES36环绕动画总帧数
SIZE520输出分辨率(宽高均为该值)
ELEV62相机仰角(度)
FPS24GIF 帧率(脚本换算为帧延迟)
COLORSCHEMETomorrowOpenSCAD 配色方案(近似白底)
OPENSCADPATH/tmp/oscad-libs库搜索路径
OPENSCAD_BIN自动探测手动指定 OpenSCAD 可执行文件路径

脚本会自动按顺序探测"OpenSCAD (Nightly)"、普通 OpenSCAD.app 与 PATH 中的openscad,找不到时提示设置OPENSCAD_BIN(benchmarks/render.sh)。渲染使用--render(manifold 完整渲染)而非--preview,以保证输出为真实几何而非 CSG 模糊预览(benchmarks/render.sh),最后用 ImageMagick 的-layers OptimizePlus -fuzz 3% -colors 200做调色板压缩并二次-strip -layers Optimize精简体积(benchmarks/render.sh)。

七、从花瓶出发:同套思路的进阶延伸

本案例的价值在于它是"生成式扭曲放样 + 布尔开壳"的最小完整范式,benchmarks 目录里同一套技术栈还能看到更进阶的变体:例如 05-naca-airfoil-wing.md 用 NACA 方程构造截面再做锥形放样(同样的linear_extrude(scale=)思路)、12-axial-turbine-blisk.md 在轮毂上排布带扭转的叶片环(把"扭曲截面"应用到了旋转机械场景)。若需要螺纹等更高层图元,CADAM 的生成约束会引导模型引入 BOSL2 的screws.scad/threading.scad(src/server/aiChat.ts),参见 03-hex-bolt-and-nut.md 的 ISO 螺纹案例。

本文以仓库 benchmarks/01-twisted-hex-vase.md 及其配套.scad/render.sh为事实依据,相关参数解析与编译链路可进一步查阅 shared/parseParameters.ts、src/utils/parameterUtils.ts、src/worker/openSCAD.ts 与 src/components/parameter/ParameterSection.tsx。

  • 人工智能
  • AI 应用
  • 前端
  • 3D渲染

【免费下载链接】CADAM

CADAM is the open source text-to-CAD web application

项目地址:https://gitcode.com/gh_mirrors/ca/CADAM
点击查看免费下载

相关推荐

上一篇:3步搞定B站视频下载:Downkyi无水印高清下载终极指南
下一篇:XUnity.AutoTranslator终极指南:5分钟让Unity游戏秒变中文版

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询