零外部模型、零外部图片贴图,同一模型(Claude Fable 5.2)用纯 Python 脚本在 Blender 5.2 中从零生成 3 个 3D 场景。
当投入成本从 $6.22 拉满到 $113.96(18 倍),代码从 1,439 行膨胀到 8,740 行,总三角面数从 12.6 万跃升至 102.8 万——这背后到底发生了什么?
最近 GitHub 上的开源项目 realcodebear/blender-fable-5.2 做了一组非常有意思的对照实验:让同一个 AI 模型在 Medium Effort(v1 快速初稿) 和 Max Effort(v2 极限投入) 两种模式下,纯粹通过编写 Python 脚本驱动 Blender 5.2 构建三个复杂度递增的 3D 场景(台灯静物、低多边形浮空岛、雨夜霓虹街道),并将最终成果烘焙导出到 Three.js 网页端进行实时 3D 交互对比。
我把这个仓库拉到本地完整拆解了一遍它的 Python 建场景脚本、GLB 烘焙管线、Three.js 预览器以及 Token 账单日志。这篇文章不聊虚的,直接从代码架构、视觉反馈闭环、WebGL 导出管线和 Token 成本结构四个维度,还原 AI 是如何“手搓”复杂 3D 工程的。
一、实验全貌:v1 与 v2 的硬核数据对比
项目规定了一个极其苛刻的前提:不允许下载任何外部 .glb/.fbx/.obj 模型,也不允许加载任何外部 PNG/JPG 贴图。所有的几何体、木纹/布料/水洼材质、灯光、相机甚至霓虹灯牌和书脊上的文字,都必须由 Python 代码在 Blender 里现场生成。
两个版本的执行方式完全不同:
- v1(快速初稿): 单次会话、通过 Blender MCP(
mcp__blender__*)连接本地 Blender GUI,一次性生成全部 3 个场景并简单微调 3 个小瑕疵。总计 29 次响应、53 次工具调用,耗时约 21 分钟。 - v2(极限投入): 主会话拆出 3 个独立子 Agent,每个 Agent 死磕一个场景,禁止使用共享 GUI MCP,全部改用无头命令行渲染并反复读图自检。总计 284 次响应、344 次工具调用,累计工作约 219 分钟。
最终产出的量化对比如下:
| 场景 | 版本 | 脚本行数 | .blend 体积 | 网页 GLB | 三角面数 | 材质数 | 烘焙图集 |
|---|---|---|---|---|---|---|---|
| 01 台灯静物 | v1 | 153 (+332 公共库) | 0.23 MB | 0.44 MB | 19,076 | 17 | 2048 px |
| 01 台灯静物 | v2 | 2,041 | 2.38 MB | 2.06 MB | 182,492 | 24 | 4096 px |
| 02 浮空岛 | v1 | 386 | 0.36 MB | 0.52 MB | 13,020 | 23 | 2048 px |
| 02 浮空岛 | v2 | 2,743 | 1.34 MB | 3.16 MB | 50,312 | 11 | 4096 px |
| 03 霓虹城市 | v1 | 568 | 0.95 MB | 7.04 MB | 94,350 | 85 | 4096 px |
| 03 霓虹城市 | v2 | 3,956 | 7.50 MB | 11.07 MB | 795,310 | 191 | 4096 px |
从总三角面数来看,v2(1,028,114 面)是 v1(126,446 面)的 8.1 倍;而从代码量来看,v2(8,740 行)是 v1(1,439 行)的 6.07 倍。
下面直观对比三个场景在 v1(快速初稿)与 v2(极限投入)下的 Cycles 最终渲染效果:
01 台灯静物(v1 vs v2):


02 低多边形浮空岛(v1 vs v2):


03 雨夜霓虹街道(v1 vs v2):


二、AI 为什么能用纯代码“造”出复杂 3D 世界?
很多人好奇:大模型没有鼠标也没有视口交互,怎么保证几十万个三角面不穿模、不浮空?拆开 scripts/v2/ 的源码后,会发现 AI 并没有去硬调用模仿人类点鼠标的 bpy.ops,而是走了一条高度工程化的程序化建模路线。
1. 放弃共享 GUI MCP,转向无头 CLI 确定性重建
在 v2 的系统提示词中,主会话明确禁止三个 Agent 调用 mcp__blender__*,因为三个 Agent 并发操作同一个 Blender GUI 会互相覆盖状态。取而代之的是无头命令行:
/Applications/Blender.app/Contents/MacOS/Blender -b --factory-startup -P your_script.py -- [options]
每次运行都从 --factory-startup 空白文件起步。由于出厂默认设置不会开启 GPU 加速,v2 脚本都在头部显式配置了 Apple Metal:
bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'METAL'
# 遍历启用所有设备后设置:
scene.cycles.device = 'GPU'
同时,为了防止三个并行 Agent 同时跑 Cycles 渲染把本机显存打爆,它们在命令行里约定了一个极其朴素但好用的原子目录锁:
while ! mkdir blender-scenes/v2/.render.lock 2>/dev/null; do /bin/sleep 3; done
<blender render command>
rmdir blender-scenes/v2/.render.lock
2. 自建 Shader Node DSL 与多材质网格构建器
在最复杂的 scripts/v2/scene3_neon_city_v2.py(3,956 行)中,模型没有满足于基础 API,而是直接在脚本顶部给自己封装了一套生产力基础设施:
NT(Shader Node DSL): 把 Blender 繁琐的节点创建与连线封装成链式调用,每个方法直接返回输出NodeSocket,用几十行 Python 就能写出带噪波扰动、凹凸和粗糙度变化的复杂程序化材质(比如雨夜柏油路面的水洼反光、霓虹玻璃反射)。MB(Multi-material Mesh Builder): 彻底绕开依赖上下文的bpy.ops.mesh.*,直接用顶点坐标、面索引与bmesh批量组装建筑立面、门窗框、自动贩卖机、带雨伞的行人和车辆,并精确分配多材质槽位。stroke font(三维笔画字体): 霓虹灯牌上的文字不是贴图,而是直接用空间折线坐标生成实体灯管曲线并赋予高强度自发光,再转为 Mesh。
3. 细节密度决定真实感
以 Scene 1(台灯静物) 为例,v1 的台灯就是“圆柱+圆锥”,书本是三个长方体;而 v2(2,041 行)补充了大量物理与叙事细节:
- 台灯增加了关节铰链、开关、电源线与灯头内壁反射;
- 书本做出了书脊凸起、书页边缘厚度,并调用系统字体生成立体书名网格;
- 桌面木纹做了方向旋转,并在桌沿单独处理了**端面木纹(end grain)**与一个旧杯印磨损痕迹;
- 盆栽叶片与橙子开启了次表面散射(SSS),马克杯上方甚至加了体积蒸汽,配合浅景深(DOF)和 1024 采样 Cycles 渲染。
三、真正的质变密码:AI 给自己写了“质检工具”
如果让大模型盲写 3,956 行 3D 坐标代码,哪怕它数学再好,一次性跑出来的画面也大概率惨不忍睹。
v2 之所以质量突飞猛进,最核心的秘密在于**“低成本渲染 → 多模态读图 → 代码修 Bug”的闭环**。查看三个 v2 脚本的命令行参数,你会发现 AI 给自己造了一整套 QA 调试工具:
--preview/--res 50 --samples 48:半分辨率、低采样快速出图,几秒钟看一眼效果,避免每次等 1080p 高采样浪费时间;--cam NAME:内置十几个质检机位(比如 Scene 1 里有top / lamp / head / books / mug / plant / fruit / front / edge / side / low,Scene 3 里有main / left / right / car / people / rail / tower / top),专门用来凑近检查有没有穿模、浮空;--crop x0,y0,x1,y1:只渲染画面中某一个局部方块,用来反复打磨单个道具的材质或光影;--debuglight(Scene 2):切到平灰灯光模式,剥离颜色干扰,专门检查低多边形山体和瀑布的剪影结构。
统计数据印证了这一点:v1 每个场景只看图检查了 2~3 次;而 v2 的三个 Agent 各自执行了 107~127 次工具调用,绝大多数都是在重复“局部渲染 → Read PNG 读图批判 → 改脚本参数”。
四、从 Cycles 离线渲染到 Three.js 网页 3D 预览
.blend 文件里的程序化节点树、体积雾和路径追踪光照在浏览器 WebGL 里是跑不起来的。为了让访客能在网页上直接 3D 旋转查看 6 个版本,项目中的 tools/export_glb.py(500 行)和 viewer/viewer.js(260 行)实现了一套非常干净的转换管线:
1. 离线烘焙与极限压缩(tools/export_glb.py)
- 坐标系与元数据同步: 将 Blender 的 Z-up 转换为 glTF 的 Y-up,把渲染相机机位、视场角(
vfov)、焦点距离以及所有光源参数写入<key>.json。 - 天空全景烘焙: 临时新建
sky_tmp场景,用等距柱状全景相机(EQUIRECTANGULAR)以 8 采样渲染2048×1024的天空贴图<key>_sky.jpg。 - 程序化材质烘焙为共享图集(Texture Atlas): 保留纯色简单材质;把所有带程序化节点树的材质重新打包 UV,在 Cycles 下分别烘焙
DIFFUSE、EMISSION(按 99.5% 分位数动态计算 HDR 缩放系数K)和ROUGHNESS,合成一张2048px或4096px纹理图集。 - 剔除体积 & 合并 Draco 导出: 丢弃雾效和蒸汽体积对象,文字/曲线转 Mesh 后合并为单个对象减少 Draw Call,最后以 WebP(质量 86)+ Draco(位置 16-bit、法线 10-bit、UV 12-bit) 导出。接近 80 万面的
S3_NeonCity_v2最终只有 11.07 MB。
2. Three.js 实时近似与性能优化(viewer/viewer.js)
- 按需懒加载与视口休眠: 只有点击按钮时才动态加载 GLB;结合
IntersectionObserver和OrbitControls的change事件控制渲染标志位,画面静止时不空转 GPU。 - 竖屏视场角自适应(
fitFov): Blender 的视角是按 16:9 横屏设计的,在手机竖屏上会自动换算 FOV 保持水平视野不被裁切。 - 效果近似补偿:
- 用
EffectComposer+UnrealBloomPass模拟霓虹灯牌泛光,并通过LOOK配置表按场景微调曝光与AgX / Filmic色调映射; - 过滤掉
energy > 1e5的探照灯(原本只靠体积雾显现),移动端自动把最大实时光源数限制在 6 盏以内; - 针对雨夜街道,在路面高度
y = 0.02处叠加一个Reflector平面配合自定义WetShader(利用菲涅尔项pow(1.0 - view.y, 3.0)与AdditiveBlending)来近似湿滑路面的倒影。
- 用
五、账单解剖:1.29 亿 Token 到底烧在了哪里?
这是整个项目最反直觉、也最具工程参考价值的部分。按 Claude Fable 5.2 API 牌价(输出 $40/M、输入 $8/M、缓存写入 $10/M、缓存重读 $0.20/M)估算,v1 与 v2 的消耗明细如下:
| 运行任务 | 响应次数 | 工具调用 | 输出 Tokens | 新输入(写缓存) | 缓存重读 Tokens | 工作耗时 | 估算成本 |
|---|---|---|---|---|---|---|---|
| v1 · 全部三个场景 | 29 | 53 | 71,461 | 156,790 | 4,273,744 | ~21 min | $6.22 |
| v2 · 台灯静物 | 76 | 107 | 303,734 | 1,254,110 | 28,469,106 | ~53 min | $30.38 |
| v2 · 浮空岛 | 96 | 110 | 401,160 | 1,524,384 | 44,557,879 | ~66 min | $40.20 |
| v2 · 霓虹城市 | 112 | 127 | 468,470 | 1,337,444 | 56,347,897 | ~100 min | $43.38 |
| v2 三 Agent 合计 | 284 | 344 | 1,173,364 | 4,115,938 | 129,374,882 | ~219 min | $113.96 |
算上主会话派发任务和验收的 $4.88,v2 总计 $118.84。
从这组数字里可以提炼出三个非常现实的结论:
- 模型“写代码”只占 40% 的钱,60% 的钱花在“读历史”:
v2 三个 Agent 输出了 117 万 Token(约 $46.93),但重读了高达 1.29 亿 Token 的历史上下文(占总 Token 量的 96% 以上)。在 76~112 轮的漫长迭代中,每走一步都要把几千行单文件代码、终端日志和之前看过的渲染图重新过一遍,上下文呈 膨胀。 - 越复杂的场景,视觉闭环收益越大:
三个场景中,霓虹城市(Scene 3) 的迭代轮次最多(112 轮)、成本最高($43.38),但也是 v1 到 v2 跨度最震撼的一个——它靠代码生生搭出了一整条包含拉面馆、24 小时便利店、街机厅、咖啡馆、行人与车流的赛博雨夜街区。 - 单文件过大是双刃剑:
v2 选择了“单文件自包含”,虽然极大降低了跨文件依赖出错率,但也导致每次读写局部代码时,上下文负担越来越重。
六、总结:给 AI 图形 / 3D 工程的三条实战启示
blender-fable-5.2 证明了一件事:AI 做复杂 3D 场景已经跨过了“能不能做”的门槛,现在的核心命题是“如何设计反馈闭环与控制上下文成本”。
- 优先用“无头 CLI + 确定性脚本”替代 GUI 交互: 可重复运行、可局部裁剪预览(
--crop)、可切换调试相机(--cam),是 AI 稳定产出的前提。 - 让 AI 自己造 QA 工具: 与其指望模型一次算对空间坐标,不如让它先写好低采样预览、灰模灯光模式和自动化几何检查,通过多模态视觉闭环自我纠偏。
- 警惕长程 Agent 的上下文膨胀: 当迭代超过 50 轮时,缓存写入与重读成本会迅速反超输出成本;合理拆分模块化文件、及时清理过期预览图上下文,是把 $40/场景压低到 $10 以内的关键优化方向。
项目地址: github.com/realcodebea…
在线 3D 对比页: realcodebear.github.io/blender-fab…