在开始动手写这篇复盘之前先交代一下背景我最近在做一个智慧仓储的数字孪生Demo技术栈没有走传统那套3ds Max手动建模 Unity场景烘焙 前端单独开发的路线而是换成了 Antigravity一个云端AI编程代理平台配合 Blender 和 MCP 协议让AI直接通过自然语言把仓库的3D模型搭出来。简单说我只需要在对话框里输入建一栋120米乘80米、高12米的钢结构仓库里面放五排双深货架Antigravity就会借助 Blender MCP 提供的工具在Blender里真实执行建模指令模型直接出现在视口中。这套打法的核心价值在于数字孪生场景的搭建从人用鼠标一点点拉变成了人描述意图、AI拆解并执行。这篇文章是上半程的完整记录重点讲清楚环境搭建、链路原理、建模实操以及我踩过的十几个坑。适合三类人看一是想尝试用AI驱动3D内容生产的开发者二是正在做仓储物流数字孪生项目但嫌建模太慢的工程师三是对MCP协议怎么落地到具体软件感兴趣的人。1. 项目全貌先搞清楚数字孪生要解决什么问题1.1 智慧仓储数字孪生到底是什么很多人一听到数字孪生就想到高大上的可视化大屏实际上落到仓储场景里它要解决的问题非常具体让管理者在一个三维空间里看到仓库的物理状态、库存状态和作业状态并且能基于这个数字镜像去做调度验证和异常预警。一个完整可用的仓储数字孪生至少包含三个层次。第一层是几何模型层也就是仓库的3D场景本身包括建筑结构、货架、托盘、AGV通道、分拣线等这一层解决的是看起来像不像的问题。第二层是数据连接层把WMS、WCS这些业务系统的实时数据接进来比如每个货位当前放了什么SKU、库存量是多少、AGV当前在哪这一层解决的是动得对不对的问题。第三层是业务逻辑层在场景上叠加规则和算法比如库存低于阈值自动报警、拣货路径自动规划、密集存储率实时计算这一层解决的是用了有没有用的问题。多数团队做数字孪生项目时时间和人力大部分耗在第一层——3D建模。尤其是仓储这种场景有大量重复结构几百上千个货位、成排的货架手动建模不仅枯燥而且改一个尺寸就要连带改一片。所以我这次的核心思路就是把最重最累的几何模型层交给AI去生成把人工精力留到数据连接和业务逻辑上。这才有了 Antigravity Blender MCP 这套组合。1.2 为什么是Antigravity Blender MCP这个组合先说结论这套组合的核心价值不是某个工具多厉害而是把建模从体力活变成了对话。传统流程里建模师用Blender手动建好模型再导出glTF给前端渲染中间还要反复沟通修改。而用AI代理驱动Blender等于把建模师也变成了程序的一部分。选型时我其实对比过几条路。一条是用Unity做数字孪生Unity在实时渲染和交互上很强但它的建模能力很弱你还是要先在Blender或3ds Max里把模型建好而且Unity的脚本开发成本和License成本都不低。另一条是直接用Three.js在浏览器里从零建模好处是没有桌面依赖但空间几何逻辑要在代码里手写生成复杂场景的效率很低。最后我选择Blender作为建模引擎是因为它免费、Python APIbpy非常完整、模型可以直接导出glTF给Three.js用这几个特点几乎就是为数字孪生场景定制的。Antigravity在这里扮演的是大脑和手。它是一个能跑代码、能操作文件、能调用外部工具的AI代理比单纯的聊天机器人强在真的会做事。它负责读取我的需求、拆解建模步骤、决定调用哪些MCP工具、检查每一步的执行结果并自动纠错。MCP则是神经和血管全称Model Context Protocol是一个把AI模型和外部工具连接起来的开放协议。有了它Antigravity才能按标准方式调用Blender里的能力而不是各写各的私有接口。这三层关系类比到人体上就是Blender是骨骼和肌肉负责最终呈现MCP是神经网络负责传递指令Antigravity是大脑负责思考和决策。下面逐一把每个环节的细节讲清楚。2. 工具链把关三个组件如何各司其职2.1 Antigravity既能写代码、又能调外部工具的AI代理Antigravity不是普通聊天机器人它的工作方式更接近一个云端的外包工程师。它有一个Browser IDE环境能执行终端命令、读写文件、安装依赖还能按MCP协议挂载你指定的服务器然后在你授权范围内调用那些服务器暴露的工具。我在这个项目里用Antigravity做了三件事。第一件是理解和拆分需求比如生成5排货架这种模糊表述它会自行推理出货架长宽高、层数列数和间距大概是合理的而不是傻等用户把所有参数都喂到嘴边。第二件是执行代码它可以在沙箱里写Python脚本也可以在需要时通过MCP把代码发到Blender里去执行。第三件是错误恢复某一步执行报错后它会读取返回的错误信息自己调整参数重试这个过程我只需要在最终结果不满意时介入。需要说明的是Antigravity更新比较频繁我在过程中遇到过更新后配置丢失的情况所以建议把MCP相关的配置文件备份一份别依赖云端同步。另外它在执行长任务时偶尔会因为超时中断处理方式后面会细说。2.2 Blender开源3D引擎为什么够用有人可能会问数字孪生的最终形态是网页可视化为什么中间要插一个桌面版Blender答案是Blender是生产端不是展示端。仓库场景的原始几何体、材质、布局先在Blender里搭建出来确认无误后导出为glTF格式再交给Three.js在浏览器里渲染展示。这样生产端和展示端各自做自己擅长的事。Blender能被AI驱动最核心的资本是它的Python API。整个Blender几乎所有的操作都暴露给了Python包括创建网格、设置材质、修改变换、组织场景层级等。AI代理通过执行一段Python代码就能完成过去需要鼠标配合键盘操作几十步的事情。这是很多其他3D软件做不到的——它们虽然有Python接口但接口覆盖度远远不如bpy这么彻底。用版本上我建议直接用Blender 4.x LTS3.x也兼容但4.x在Python API上更稳定。要注意的是Blender自带的Python环境跟我们平时用的系统Python是隔离开的装第三方包要格外小心这点在后面踩坑部分会专门说。2.3 MCP把AI的意图变成软件的指令MCP的全称是Model Context Protocol它解决的问题很直白每个AI应用都要对接大量外部工具如果每个工具都单独写一套集成方式维护成本会爆炸。MCP提供了一组标准原语——工具Tools、资源Resources、提示词PromptsAI客户端按照这套标准去发现和调用外部能力就像USB把各种外设统一成一个接口。落到我们这个项目里MCP要桥接的是AI模型和Blender两个完全异质的系统。Blender本身并不认识MCP所以实际架构是两段式Blender内部跑一个WebSocket服务负责接收JSON指令并调用bpy执行Blender外部跑一个MCP中转进程一端用MCP协议跟Antigravity通信另一端通过WebSocket跟Blender通信。为什么中间要加这么一层中转而不是让Antigravity直连Blender原因有两个。一是Blender没有现成的MCP服务实现二是因为如果把这层桥接做得足够规整以后换个AI客户端比如其他支持MCP的IDE只需要改配置不用动Blender侧的任何代码。这个解耦的价值在多工具协同的项目里会越来越明显。3. 环境搭建与链路打通这一部分是整个项目里最容易被教程一句话带过、但实际上坑最多的地方。我把完整步骤和背后的原理一起写出来照着做基本能一次通。3.1 部署Blender侧WebSocket服务首先安装Blender确保能正常启动。然后部署Blender MCP服务端目前社区里比较流行的开源方案是一个叫blender-mcp的项目具体路径自己搜一下就有它本质上是把Blender变成一个可被远程控制的Python执行环境。安装方式一般是下载项目文件把它放到Blender的用户插件目录Edit → Preferences → Add-ons → Install或者手动复制到scripts/addons/目录然后勾选启用在Blender的侧边栏或脚本工作区里找到对应面板点击启动MCP Server。启动成功后Blender会创建一个监听在127.0.0.1:9876不同版本端口可能不同的WebSocket服务这个端口就是MCP中转进程要连接的地址。我重点想提醒的是不要以为启动了服务就万事大吉。Blender侧这个服务本质上是一个长驻的Python进程它把接收到的指令丢进Blender的执行上下文去跑。第一次启动时一定要看Blender系统控制台Window → Toggle System Console里有没有打印端口号和waiting for connection之类的字样如果没打印说明服务根本没起来后面连不上别急着怀疑网络。注意Blender的插件目录在不同操作系统上差别很大Windows一般在%APPDATA%\Blender Foundation\Blender\版本号\scripts\addonsmacOS在~/Library/Application Support/Blender/...Linux在~/.config/blender/...。装错目录会出现插件列表里看不到的问题。3.2 注册MCP中转服务Blender侧起来之后还需要一个MCP中转进程。这一步要单独开一个终端进入blender-mcp项目里那个bridge/server目录安装Python依赖主要是mcp和websockets这两个包然后运行入口脚本。启动参数里一般会要求填Blender WebSocket服务的地址和端口以及中转服务自己监听的端口。这里有一个常见的坑MCP官方SDK的导入方式在不同版本里有差异如果启动时提示ModuleNotFoundError: No module named mcp先确认你是不是把包装到了当前Python解释器里而不是装进了Blender自带的Python。我自己遇到过装错环境导致bridge起不来的情况排查办法是先在终端里python -c import mcp验证一遍。中转进程起来后把它暴露的MCP服务地址配置到Antigravity里。在Antigravity的MCP配置界面新增一个服务器填写名称比如blender协议选择Streamable HTTP或WebSocket地址填中转进程监听的本地端口。以我用的配置习惯大体是这样的JSON结构——{ mcpServers: { blender: { transport: streamable_http, url: http://127.0.0.1:3000/mcp } } }不同版本客户端的配置字段名可能略有差异但核心就两个信息传输方式和地址。配置完保存并重连在Antigravity的工具列表里如果能看到create_object、execute_blender_code、get_scene_info这一类的工具名说明MCP链路已经通了。记得把Blender主窗口保持在打开状态别最小化到托盘Blender在某些无头状态下会暂停执行。3.3 首次联调验证链路通了之后先别急着建大场景用最小命令验证一遍全链路。我在Antigravity对话框里输入的第一句是在原点创建一个2×2×2的立方体命名为test_box然后打印场景里所有物体名称。这句话背后发生的事情值得拆开讲一遍因为它解释了整条链路的运作方式。Antigravity收到请求后不是直接把这句话原样发给Blender而是由模型判断这是一个需要调用外部工具的任务于是通过MCP客户端发出工具调用请求比如调用execute_blender_code参数是生成立方体的Python代码。中转进程收到MCP请求后把代码封装成JSON消息通过WebSocket推给Blender。Blender侧的监听服务接收到消息在自身的Python上下文里执行bpy.ops.mesh.primitive_cube_add()生成物体然后把执行结果成功/失败、返回数据一路原路返回。整个过程看起来像一次水管的单向流动实际上是双层双向通道。第一次联调你可能会遇到两种结果要么顺利看到立方体生成要么看到某个环节报错。如果报错按第5部分的排查表去定位绝大多数问题出在Blender侧服务没启动或中转进程依赖缺失这两个原因上。4. 仓储数字孪生场景的建模实操链路通了之后真正有意思的部分才开始。我按照建筑主体 → 货架系统 → 数据联动的顺序把一个120米×80米的智慧仓储场景逐步在Blender里搭了起来。4.1 搭建主体结构第一件事是确认坐标系统。Blender默认以米为长度单位而且原点就是世界坐标系的原点这跟仓储图纸的单位习惯正好一致。我在初始提示里直接明确尺寸以原点为中心生成长120米、宽80米、高12米的仓库主体底面用平面四周立墙顶部用人字形桁架示意。这个表述本身是有讲究的——以原点为中心决定了AI生成物体时的坐标计算方式先底面后墙体决定了代码执行次序。Antigravity会把这段需求拆解成几步先创建一个平面并缩放到120×80然后在四条边分别创建立面墙板接着在顶部生成两排倾斜的屋顶板模拟人字桁架。每一段都是独立的MCP工具调用某一步失败了它会自己看错误信息重试。我不需要关心中间的代码细节只需要检查每一步返回的success字段和生成的物体名称。值得注意的一个细节是AI默认生成的墙是一个厚度为0的平面。这在可视化层面没问题但如果后续要做碰撞检测或者剖切展示就需要把墙体改成有厚度的立方体。我的做法是在后续指令里补充所有墙体厚度设为0.3米AI会更新之前的物体而不是再生成一批新的。这说明什么说明跟AI协作建模描述越具体返工越少——它不是读心术但你能教会它。4.2 生成货架系统仓库主体搭好后我开始生成货架。真实的仓储场景中货架是重复度最高的结构所以这也是最能体现AI建模效率的地方。我的需求描述是在仓库内部生成5排双深货架每排20列5层托盘尺寸1.2米×1.0米层高1.5米货架之间留3米宽的AGV通道。这一步的代码逻辑其实很有代表性AI生成的脚本大概是这样的简化结构——import bpy # 每排货架的基础尺寸 tray_w, tray_d 1.2, 1.0 level_h 1.5 cols, levels, rows 20, 5, 5 lane_w 3.0 # 双深货架两列托盘背靠背 for r in range(rows): for c in range(cols): for l in range(levels): x r * (tray_d * 2 lane_w) y c * (tray_w * 2) z l * level_h bpy.ops.mesh.primitive_cube_add(size1.0, location(x, y, z)) obj bpy.context.object obj.scale (tray_w / 2, tray_d / 2, 0.03) obj.name fRack_R{r}_C{c}_L{l}这个脚本的核心思路是循环生成 按命名区分每一个货位托盘都是一个独立可命名的对象。为什么要强调独立对象而不是合并成一个网格因为后面做数据联动时要按货位坐标定位库存状态独立对象意味着可以单独改颜色、单独响应数据变化。代价是物体数量多后面第5部分会讲怎么在性能上兜底。货架生成后我还让AI在通道地面上画了AGV导引线一条条细长的平面以及每个货位上方添加了文字标注货位编码。Blender里添加文字可以用bpy.ops.object.text_add()这一步用鼠标做非常繁琐但用代码指令做就是几行循环的事。4.3 接入实时数据驱动场景建完只是静态模型数字孪生还得活起来。我做的第一版动态联动是库存状态可视化模拟一份WMS库存数据把库存量低于阈值的货位标记为红色正常货位标记为绿色积压货位标记为蓝色。实现方式依然是让AI写代码但这次的代码不是建物体而是改材质。核心就是一个更新材质的函数我在Antigravity里输入需求后它生成的代码逻辑类似下面这样——import bpy def set_slot_color(slot_name, color): obj bpy.data.objects.get(slot_name) if obj is None: return {success: False, error: f{slot_name} not found} if not obj.data.materials: mat bpy.data.materials.new(slot_name _mat) mat.use_nodes True obj.data.materials.append(mat) mat obj.data.materials[0] bsdf mat.node_tree.nodes.get(Principled BSDF) bsdf.inputs[Base Color].default_value (color[0], color[1], color[2], 1.0) return {success: True, slot: slot_name, color: color} # 示例批量更新 inventory {Rack_R0_C0_L0: 0.88, Rack_R0_C0_L1: 0.12} for slot, ratio in inventory.items(): if ratio 0.2: set_slot_color(slot, (0.9, 0.1, 0.1)) elif ratio 0.8: set_slot_color(slot, (0.1, 0.3, 0.9)) else: set_slot_color(slot, (0.1, 0.8, 0.2))把这段逻辑封装成MCP工具之后理论上只要上游数据一变化调用一次工具所有货位颜色就能刷新。不过这一版我只做了数据驱动的颜色联动真正从WMS接口拉实时数据、按时间戳增量更新属于下半程的内容后面预告里再说。我这里特别想讲一个实操心得跟AI协作改模型不要一步一步让它加一个、再看一眼而是把每次修改想象成编程里的函数调用。你可以让AI把整套货架生成逻辑封装成一个带参数的工具——传目标准、列数、层数它就生成一整套布局传新的库存字典它就刷新颜色。这样做的效率提升是数量级的也是这套组合的核心玩法。5. 踩坑实录与排查速查表这部分内容是我最想写给后来者的。整个项目做完踩过的坑加起来少说十几个我按类别整理成一张速查表每个问题都附上了我当时实际的处理方式。现象可能原因处理方式Antigravity提示MCP连接失败Blender侧服务没启动或中转进程没起来先看Blender系统控制台有没有打印端口再检查终端里bridge进程是否存活启动bridge时报ModuleNotFoundError依赖装进了错误的Python环境在当前终端里python -c import mcp, websockets验证不行就在项目里新建venv重装Antigravity执行任务中途报execution terminated due to error单次任务执行时间过长超出沙箱限制或某段代码抛了未捕获异常把大任务拆成多步小任务在生成代码里强制try/except并返回错误信息访问某些MCP地址返回403地址鉴权失败或沙箱网络策略不允许访问非白名单地址确认地址是本机的127.0.0.1不要把需要鉴权的密钥明文写在配置里生成物体位置跟预期偏差很大描述里没指明坐标系基准在需求里明确写上以原点为中心堆垛方向沿X轴这类空间约束物体名称重复AI用了固定命名第二次生成没有清理旧物体在生成前自动清理工具内先按前缀删旧对象再创建新对象Blender卡顿、界面无响应一次性生成了过多独立物体改用Collection实例化instance collection或降低货位细分材质颜色不生效物体没有材质槽或Principled BSDF节点被重建先检查obj.data.materials是否为空确保用bsdf.inputs[Base Color].default_value而不是直接改diffuse_color除了这些对查表就能解决的问题还有几个属于经验级的坑值得单独展开。第一个是bpy.ops的执行上下文问题。Blender的有些操作比如删除、复制依赖当前的活动对象和模式如果脚本在执行bpy.ops.object.delete()时没有先做全选操作可能只删了一半或者报错。AI写的脚本经常忽略这一步我的办法是在工具层就做防护每次执行一段高风险代码前主动bpy.ops.object.select_all(actionDESELECT)再按需选择目标。第二个是版本差异。Blender 3.x和4.x之间部分bpy.ops的参数签名有细微变化如果你在社区找到的示例代码跑不通先看看版本。AI模型的知识截止时间也不一定覆盖最新版本遇到报错别硬跑让它阅读本机Blender的API文档再改代码。第三个是场景备份习惯。因为AI操作是批量执行万一某个循环逻辑写错可能把已经建好的货架全删了。我现在的习惯是每完成一个里程碑比如货架建完、墙体建完就用bpy.ops.wm.save_as_mainfile()存一个版本。这条经验用血泪换来的——有次我只顾着玩数据联动忘记备份结果AI一次误删直接回到解放前。第四个是Antigravity更新出错的问题。这个平台版本迭代很频繁有时更新后MCP配置会丢失或者原来能用的工具突然变了个名字。遇到这类情况我的建议是先把本地的MCP配置文件和工具列表截图保存更新后按截图快速恢复如果是平台侧的临时故障等一阵再重试通常就能恢复别反复重装客户端折腾。6. 上半程小结这套组合值不值最后一章不打算堆总结就说我个人实测下来的真实体会。Antigravity Blender MCP这套组合在快速搭建数字孪生场景原型这个场景下效率确实是传统手动建模的十倍不止。过去一个熟练的建模师用手动方式搭一个五排货架的仓库场景怎么也得大半天甚至一天现在我在对话框里输入需求全程盯着一行行返回结果不到半小时就能出一个像模像样的静态场景。而且修改迭代非常快觉得货架间距不合适说一声AI就整体调整这在手动流程里意味着推倒重来。但我也要泼一盆冷水这套组合适合的是原型验证和批量生成真正要上生产环境模型精度、性能优化、数据安全这些硬骨头一个都躲不掉。AI生成的建模代码往往是能用但不精致面数控制、UV整理这类脏活还得人工把关。再就是依赖关系比较脆弱三个组件任何一个更新都可能破坏链路日常使用要有随时修复的心理准备。最后预告一下下半程的内容。这篇文章只讲了静态场景搭建和基础的颜色联动下半程我会重点写三件事一是如何把真实的WMS/WCS数据流用WebSocket或消息队列接到Blender场景里实现货位状态、AGV位置的实时刷新二是Blender模型如何导出为glTF并在Three.js网页端做轻量化展示三是当场景规模从几千个物体涨到上万个物体时怎么用实例化、LOD和烘焙技术保住流畅度。如果你也在用AI驱动3D工具做数字孪生或者已经在搞Blender MCP相关的尝试欢迎把遇到的问题和折腾出来的方案评论在下面下半程写的时候我会把大家的语音汇总进去。