资讯动态

AI写代码生成参数化3D模型:螺旋楼梯实战与程序化建模思路

发布时间:2026/9/17 7:49:01 来源:尧图企业网站定制
先聊一个我最近特别有感触的现象现在到处都能看到“输入一句话AI生成3D模型”的工具你给它一段描述或者一张图片它就能吐出一个GLB或者OBJ文件看起来确实唬人。但你把文件拖进自己的项目里试试十有八九会血压升高——拓扑是乱的UV是花的想改一个尺寸只能重新生成一次稍微一改参数整个模型就废了。这种“死模型”在摆件展示、概念草模这种一次性场景里还能凑合一旦你要做游戏资产、机械结构、建筑可视化、数字孪生这类正经工程项目基本就是给自己挖坑。所以我现在的倾向特别明确别让AI直接吐3D模型文件让它写生成模型的代码。这个系列我打算分成上下两篇。上篇先把思路讲透再带大家完整跑通一个“AI写代码生成参数化3D模型”的实操案例从写提示词到跑起来、修bug、加参数面板全程记录。下篇再往深了做场景扩展和导出流程。今天这篇适合所有被AI直接生成模型坑过的人也适合想做程序化建模但不知道从哪下手的开发者。1. 两条路线让AI吐模型文件还是让AI写代码1.1 AI直出3D模型的三个现实问题先给AI直接生成3D模型的路线说句公道话。现在的图片生成3D、文本生成3D工具在“出图速度”上确实很强几秒钟就能给你一个看起来有模有样的模型甚至还能带贴图。但在实际工程里这条路有几个绕不开的问题。第一个问题是模型是“死”的。工具生成出来的是一个已经烘焙好的mesh顶点坐标、三角面、UV都是定死的。你想把台阶高度从0.16改成0.2没有这个参数只能重新生成一次。你想把一圈24级台阶改成36级大概率得整个重来。这种结构化信息缺失是AI直出模型最大的硬伤。第二个问题是拓扑质量不可控。AI直出的模型经常出现非流形边、重叠顶点、朝向不一致的面面数分布也很随意有些地方密得离谱有些地方又薄得能透光。这类模型放进游戏引擎做碰撞体、做LOD或者丢给后期软件做动画绑定都会出各种莫名其妙的bug。第三个问题是工程集成难。直出的模型在展示场景里转一圈没问题但真正常规生产需要的东西——干净的层级结构、合理的命名、可碰撞的几何体、不同LOD级别的减面版本——几乎都没有。你拿到手的只是一坨“长得像某样东西”的mesh而不是一个可以进入生产管线的资产。当然我不是说AI直出模型一无是处。如果是做摆件、做3D打印前的快速概念稿或者给客户看一个“大概是这个意思”的外观方案它非常高效。但它的定位应该是“灵感草图”而不是“工程交付物”。1.2 代码生成模型本质上是在做“参数化资产”那让AI写代码生成3D模型走的是什么路线呢本质上这是把模型从“一份数据”变成“一段程序”。举个例子。我要生成一个螺旋楼梯传统流程是手动建模一个台阶一个台阶地摆AI直出流程是输入“生成一个现代风格螺旋楼梯”得到一坨动不了的mesh换成代码生成流程AI给我写的是一段带参数的JavaScript函数——台阶数量、总旋转角度、台阶宽度、扶手高度全部是变量。这带来的好处是质的飞跃。第一是参数化改一个变量整个模型联动变化24级台阶想要36级改个数字就完事。第二是可版本管理代码可以进Git每次改动都能diff出了问题可以回滚这在团队协作里太重要了。第三是可复用今天生成的是螺旋楼梯明天换个参数就是旋转坡道再换个参数就是盘山公路的一段同一套几何逻辑到处复用。说白了直接生成模型是“请人画一张一次性画像”生成代码是“教会别人一套可定制的肖像模板”。后者前期的思考成本高一点但一旦跑通改动成本几乎为零。1.3 什么时候该选哪条路一张决策表我在实际项目里总结了一个粗略的决策表不一定适合所有场景但大方向不会错项目类型推荐路线原因概念展示、外观草图AI直出模型快够看不用管工程细节游戏资产、程序化地编AI写代码生成需要LOD、碰撞体、可控复用机械零件、3D打印件AI写代码生成尺寸精确、可调参数布尔运算更可靠建筑方案比选AI直出代码辅助前期用直出快速沟通定稿后再代码化翻模数据可视化、数字孪生AI写代码生成模型跟随数据动态变化是刚需角色、生物模型AI直出为主有机形态不适合纯参数化代码做辅助加装配件判断标准就一句话这个模型接下来是一锤子买卖还是会被反复修改和复用如果是前者怎么快怎么来如果是后者老老实实走代码生成。这篇文章剩下的内容全部围绕后者展开。2. 让AI写3D代码之前先把这三件事想清楚2.1 把“感觉”翻译成几何规则很多朋友让AI写3D代码翻车根源不是AI不行而是需求本身就没说清楚。AI不理解“现代感”“科技感”“好看”这种形容词它理解的是“半径0.5米的圆柱体”“绕Y轴每15度放置一个”“从底部到顶部颜色渐变”。所以让AI干活之前你得先把设计意图翻译成几何规则和参数。我习惯先画一个需求拆解表想做什么东西就列出来它由哪些几何体组成每个几何体由哪些参数控制。举个例子我想做一个参数化塔楼视觉目标几何规则需要控制的参数下粗上细的塔身圆台体半径随高度线性收窄底部半径、顶部半径、总高度螺旋上升的阳台层板沿圆台螺旋阵列的扁圆柱层数、旋转总角度、层板厚度窗洞布尔运算或贴图模拟开窗比例、洞的尺寸塔冠圆台球体组合或者圆锥塔冠高度、倾斜角度这张表一列出来AI需要什么代码、生成什么函数、参数怎么设计就已经清清楚楚了。AI不是设计师它是个效率极高的实习生你给它越明确的规则它给你的结果越靠谱。2.2 选对载体Three.js、Blender Python、OpenSCAD还是其他让AI写3D代码首先得选一个“写作环境”。同一个螺旋楼梯在Three.js里写JavaScript、在Blender里写Python、在OpenSCAD里写脚本、在Unity里写C#完全是四套思路。选错载体后续会很难受。我自己的选型标准是这样的Three.js浏览器直接跑零安装改完代码刷新页面就能看到效果。适合产品原型、网页交互、数据可视化、快速验证想法。这也是今天实操案例用的方案对新手最友好跟其他人同步效果也方便。Blender Python目标是一张渲染图或者最终要导出到其他DCC工具的美术资产选这个最合适。可以直接在Blender里跑脚本生成模型配合Cycles渲染器直接出图。OpenSCAD做机械件、3D打印件首选。它是CSG构造实体几何建模思路用盒子、圆柱体做布尔运算尺寸精度极高代码极其直观。Unity/Unreal C#/C目标是游戏内动态生成、玩法驱动生成那就在引擎里写。这类需求通常跟AssetBundle、内存管理耦合脱离引擎写没有意义。选型的核心原则就一条你的模型最终要在哪里被使用代码就在那个环境里写。别在Three.js里生成一个精妙的模型结果发现项目是Unity的还得手动转换那就白干了。2.3 提示词模板我实测过的高质量版本同样的需求提示词写得好不好AI给你的代码质量能差一个量级。我试过很多风格最后固定下来一个模板通用性很强你是一位精通Three.js的3D工程师。请帮我用Three.js创建一个参数化螺旋楼梯 1. 所有几何尺寸都要在代码开头的params对象中声明方便统一调整 2. 台阶用BoxGeometry实现围绕中心柱螺旋上升每级台阶的高度和旋转角度由参数控制 3. 需要添加环境光和方向光相机放在能看到整体结构的角度 4. 添加一圈螺旋扶手用TubeGeometry配合曲线实现 5. 代码使用ES module方式从CDN引入three输出完整HTML文件 6. 添加中文注释保持代码整洁 7. 直接打开HTML文件就能在浏览器中运行。拆解一下这个提示词为什么有效。第一句“你是精通Three.js的3D工程师”是角色限定AI生成代码时会倾向于用更专业的写法。第二到第四句是功能需求每个功能都跟一个具体API绑定比如“台阶用BoxGeometry”“扶手用TubeGeometry配合曲线”这比笼统说“做一个楼梯”要精确得多。第五句和第七句是运行环境约束明确告诉AI必须输出一个能直接跑的完整HTML而不是一段必须你自己拼装的碎片。第六句是代码质量要求。这套模板的关键在于角色、功能、环境、质量四个维度全部覆盖。你可以根据自己的项目替换“螺旋楼梯”部分其他骨架保持不变。3. 完整实操让AI写一个参数化螺旋楼梯3.1 第一版提示词与初始代码现在就按上面的模板开始实操。我把提示词发出去AI很快就给了一份完整代码。核心部分大概长这样// 场景、相机、渲染器 const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); camera.position.set(6, 7, 8); camera.lookAt(0, 3, 0); const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 灯光 scene.add(new THREE.AmbientLight(0xffffff, 0.6)); const dirLight new THREE.DirectionalLight(0xffffff, 1.2); dirLight.position.set(5, 10, 7); scene.add(dirLight); // 参数集中管理 const params { steps: 24, // 台阶总数 totalAngle: Math.PI * 2, // 总旋转角度 stepWidth: 1.2, // 台阶径向长度 stepDepth: 0.4, // 台阶沿周向的宽度 stepHeight: 0.16, // 每级台阶高度 centerRadius: 0.2, // 中心柱半径 railHeight: 0.9, // 扶手高度 }; // 生成台阶 for (let i 0; i params.steps; i) { const angle (i / params.steps) * params.totalAngle; const box new THREE.Mesh( new THREE.BoxGeometry(params.stepWidth, params.stepHeight, params.stepDepth), new THREE.MeshStandardMaterial({ color: 0xb0a08a, roughness: 0.7 }) ); box.position.y params.stepHeight * i; const r params.centerRadius params.stepWidth / 2; box.position.x Math.sin(angle) * r; box.position.z Math.cos(angle) * r; box.rotation.y -angle; scene.add(box); } // 中心柱 const totalHeight params.steps * params.stepHeight; const pillar new THREE.Mesh( new THREE.CylinderGeometry(params.centerRadius, params.centerRadius, totalHeight, 24), new THREE.MeshStandardMaterial({ color: 0x8a7a6a }) ); pillar.position.y totalHeight / 2; scene.add(pillar);把这段代码保存成HTML跟Three.js的CDN引入拼在一起浏览器一打开一个螺旋楼梯的基本骨架就出来了。第一版能跑但细看问题不少台阶之间没有上下错开的视觉层次感因为高度是线性叠加的看起来更像一个旋转坡道被切成块而且扶手那一部分直接没生成。这说明AI对“螺旋楼梯”的理解还不够精确需要靠迭代来收敛。3.2 让AI自己修bug的正确姿势第一次跑通后我发现三个问题扶手缺失、相机视角太近、台阶的旋转方向跟预期相反。很多人这时候会把三个问题一次性发给AI让它“一起修一下”结果往往越修越乱。我的经验是一次只让AI修一个问题修完立刻验证再提下一个。第一轮我让AI补扶手。提示词很简单“请在上面的代码基础上给螺旋楼梯添加外侧扶手使用TubeGeometry生成沿楼梯外侧边缘从底部延伸到顶部。扶手高度由params.railHeight控制管道半径0.04。”AI给出的方案是用CatmullRomCurve3采样楼梯外侧轨迹再用TubeGeometry沿着轨迹生成管道。// 生成螺旋扶手 const railPoints []; const railRadius params.centerRadius params.stepWidth * 0.95; const segments params.steps * 16; for (let i 0; i segments; i) { const t i / segments; const angle t * params.totalAngle; railPoints.push(new THREE.Vector3( Math.sin(angle) * railRadius, params.stepHeight * params.steps * t params.railHeight, Math.cos(angle) * railRadius )); } const curve new THREE.CatmullRomCurve3(railPoints); const railTube new THREE.Mesh( new THREE.TubeGeometry(curve, railPoints.length - 1, 0.04, 8, false), new THREE.MeshStandardMaterial({ color: 0x5a4a3a }) ); scene.add(railTube);这里有两个细节值得说。第一railPoints的采样数量我用的是steps乘以16也就是每个台阶之间采样16个点曲线平滑度足够如果采样点太少扶手会呈现明显的折线段。第二TubeGeometry的第二个参数是分段数我直接用了railPoints.length - 1等于每两个采样点之间一段分段足够密了。第二轮我让AI调整相机初始位置。原始代码里camera.position.set(6, 7, 8)在台阶数量少的时候刚好台阶一多楼梯总高超过5米相机就只能看到局部。我让AI把相机改成根据楼梯总高度动态计算“请修改相机初始化位置让它根据params.steps和params.stepHeight自动计算合适的观察距离保证整个楼梯在视野内。”AI给出的修改很朴素但很实用const totalHeight params.steps * params.stepHeight; const distance Math.max(8, totalHeight * 0.8); camera.position.set(distance * 0.8, distance * 0.7, distance); camera.lookAt(0, totalHeight / 2, 0);这就把“手动调参数”变成了“自动适配”以后无论楼梯多高打开页面总能看到全貌。3.3 加上控制面板把“调设计”变成“拖滑块”楼梯能看、能跑了但每次改参数还得去代码里改数字不算真正的“参数化”。第三步我让AI加了一个简单的控制面板用HTML原生的range滑块来控制主要参数改设计不用碰代码。div idcontrol styleposition: fixed; top: 10px; left: 10px; background: rgba(0,0,0,0.7); color: #fff; padding: 12px; border-radius: 8px; font-size: 13px; z-index: 999; label台阶数 input typerange idsteps min6 max48 step1 value24/labelbr label总旋转角 input typerange idangle min180 max720 step15 value360/labelbr label扶手高度 input typerange idrail min0.4 max1.4 step0.05 value0.9/label /div配合的交互逻辑是监听滑块变化然后清空场景里已有的台阶、中心柱、扶手用新参数重新生成一遍。这是参数化建模最核心的交互模式——改参数重新生成再渲染。function rebuild() { // 清空旧的生成结果 scene.children .filter(obj obj.userData obj.userData.generated) .forEach(obj scene.remove(obj)); buildStairs(); buildPillar(); buildRailing(); }这里有个工程细节容易踩坑灯光、相机、渲染器这些是“场景基础设施”重建模型时不能一起清掉否则页面就废了。我给所有动态生成的物体加上userData.generated标记清理时只清这些基础设施保留。加了滑块之后我实测了几个极端参数组合台阶数调到48、总旋转角调到720度楼梯变成一个两圈的高螺旋塔视觉效果立刻就不一样了台阶数调到6、旋转角180度它又变成了一个矮矮的旋转坡道。同一个模型不同参数完全是不同的建筑部件这就是参数化的魅力。4. 容易翻车的几个坑和我的排查顺序4.1 页面白屏先查这四样AI生成代码第一次打开白屏的概率不低。从我试过的案例来看90%以上逃不出这几个原因排查顺序也很固定。第一个是浏览器控制台有没有报错。按F12打开控制台红色报错信息是AI代码的问题所在直接把报错贴回给AI大部分都能秒修。第二个是CDN资源能不能正常加载。Three.js在HTML里通常用importmap或URL直接引入如果页面白屏且控制台有类似“Failed to resolve module specifier”的报错八成是CDN地址的问题。解决办法是换一个稳定的CDN地址或者把Three.js下载到本地引入。第三个是file://协议导致的模块加载限制。用ES module方式引入Three.js直接双击HTML文件打开很容易因为浏览器安全策略而加载失败。我的建议是起一个本地HTTP服务Windows下可以用VS Code的Live Server扩展或者用Node环境跑一行npx serve。macOS和Linux系统就更简单了直接在目录下执行python3 -m http.server就能解决。第四个是WebGL兼容性。老一点的设备、某些远程桌面环境、虚拟机里WebGL可能不可用。控制台会出现制WebGL相关报错这种情况只能换设备或者让AI改成非WebGL渲染方案。按这个顺序排查绝大多数白屏问题十分钟内能解决。我最开始做的时候不知道顺序每次打开白屏就慌其实大多数问题都是CDN和file://协议这两个坑。4.2 模型长残了的三种典型错误代码能跑、页面有东西但模型长得不对这种情况比白屏更让人头疼。螺旋楼梯案例里我遇到三种典型错误顺便把排查方法一起写了。第一种是方向反了。台阶应该是逆时针螺旋上升结果AI生成的是顺时针或者台阶的朝向跟行进方向不一致。这个问题通常是rotation.y的符号问题。排查时我把台阶数量临时改成6再用Wireframe材质显示线框立刻就能看清每个台阶的旋转关系。让AI改成“rotation.y -angle”还是“ angle”试一次就知道。第二种是台阶浮空或者嵌进中心柱。台阶位置的计算公式里r centerRadius stepWidth / 2如果centerRadius设得太大台阶就会嵌进柱子如果stepWidth比实际需要的窄台阶又会离柱子太远浮在空中。这个方法要说原理其实很简单就是极坐标换算但AI生成代码时很容易把半径算错导致整个楼梯看起来是“散架”的。第三种是扶手断裂。扶手用TubeGeometry生成如果曲线采样点数太少或者分段数不够扶手就会呈多边形折线状看起来像坏了一样。解决方法是把采样点数提高比如我用的steps * 16如果还不够继续提高倍率。排查模型问题时我强烈推荐一个技巧把材质临时替换成MeshNormalMaterial颜色会按照面的朝向显示哪里法线反了、哪里面重叠了一眼就能看出来。平时用MeshStandardMaterial带光照渲染很多几何问题会被光影掩盖。4.3 让AI持续帮你改代码的小技巧代码生成模型不是一次交互就收工它是一个持续迭代的过程。我在这个螺旋楼梯项目里来回跟AI沟通了七八轮总结出几个特别管用的技巧。第一报错信息原样贴回去不要自己翻译。AI学习过海量代码错误它看到原始报错往往能直接定位问题。你自己翻译一遍反而丢失信息。第二一次只提一个问题。跟AI沟通就像跟一个注意力有限的同事协作你说“顺便把扶手也加一下”它真的会顺便但经常做得马虎。三轮对话解决三个问题比一轮对话解决三个问题效果要好得多。第三把你的期望量化。不要说“让相机看起来舒服一点”要说“让相机距离场景中心的距离等于楼梯总高度的0.8倍让相机高度等于楼梯总高度乘以0.7”。数字说得越细AI输出的代码越准确。第四善用多模态。如果你用的AI工具支持图片输入把当前效果截图丢给它再配一句“现在的问题是扶手断成两截”它能直接看到你说的是什么问题。这个能力对3D可视化调试特别实用比来回用文字描述空间关系高效太多了。4.4 一段踩坑后的避坑清单最后整理一份避坑清单都是我这段时间踩过的坑每条背后都有一次翻车经历单位要写死。是米还是厘米提示词里必须明确。AI默认写的是抽象单位如果后续要导出3D打印尺寸就不对了。坐标系要确认。Three.js是Y轴朝上的右手坐标系Blender是Z轴朝上AI有时候会混淆。换环境之前先对齐坐标系。对称操作用变量。左右扶手、对称装饰这些成对出现的结构务必用同一个参数驱动别在代码里写死两个不同数值。参数要写边界。给提示词时说明每个参数的合理范围比如台阶数6到48AI在做参数校验时会更用心。灯光不要嫌多。程序化生成的模型经常会因为朝向问题出现一大片阴影一个环境光加一个方向光是最低配置如果模型看过暗再加一个半球光补光。先跑通再优化。第一版代码哪怕效果很粗糙只要结构对后面都好说。不要一上来就让AI生成“光照特别漂亮、材质特别精细、带粒子特效”的版本代码复杂到一定程度AI自己也会出错调起来更费时间。5. 上篇收尾为什么我会一直用“AI写代码”这条路这次实操做下来我的体会是让AI写代码生成3D模型学习成本不高但收益真的很高。整个过程不只是得到一个螺旋楼梯更是在跟AI一起建立一种“规则化思考”的习惯——楼梯不是一堆三角形而是台阶数、旋转角度、扶手高度这些参数之间的数学关系。AI帮我写代码我帮AI拆解几何规则这种协作方式比让AI直接吐模型文件踏实得多。我个人现在的工作习惯是把这类AI生成的代码按项目归档成模板下次做类似的东西直接拉出来改参数。比如这个螺旋楼梯的代码改成旋转坡道只需要把台阶高度降为零改成灯塔只需要把中心柱加粗、在顶部放一个发光球体。这类复用效率是AI直出模型完全给不了的。下篇我打算做两个方向的延伸第一把这个螺旋楼梯从单个构件扩展成一个小型场景比如一个参数化的瞭望塔加上周边地台第二把生成结果导出成GLB放到其他引擎和工具里用。如果你跟我一样不想被“死模型”困住建议动手跑一遍这个案例。下一次面对3D需求你多半也会毫不犹豫选择让AI写代码而不是让它吐文件。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价