AI 工程

叫 coding agent 直接開 Blender:一行 CLI 把 3D 建模變成寫 Python

一句 prompt、2 分 39 秒,就有一張可編輯的 3D 場景

2026-09-05,Simon Willison 在他的 TIL 站上貼了一篇〈Using Blender with coding agents on macOS〉。做法簡單到有點反高潮:從 blender.org 裝好 Blender 桌面版,然後對 coding agent 說一句話——

Use the already install /Applications/Blender to render a scene of a pelican riding a bicycle

他用的是 ChatGPT macOS 應用程式裡的 Codex 模式、GPT-6 Astra(Medium)。2 分 39 秒後,agent 交出一張鵜鶘騎腳踏車的 3D render,外加一個能在 Blender 裡繼續拉的 .blend。接著他追加兩輪:OK add a background and a lot of flair(3 分 51 秒)、OK make it a whole lot better(5 分 59 秒),畫面從棚拍白底一路長成海邊木棧道的日落嘉年華——有海灘小屋、彩旗、氣球、遠方帆船。

這些時間、prompt、產物都在 Simon 的 TIL 和他開的 repo simonw/gpt-6-astra-blender-pelican-bicycle 裡,我沒有 macOS 機器可以照樣重跑,以下凡是他回報的數字我都會標明。

重點不是鵜鶘。重點是這個認知轉換:Blender 這種重度 GUI 工具,對 coding agent 來說根本不是 GUI 工具,而是「一個帶 Python API 的 CLI」。你不需要 MCP server、不需要裝外掛、不需要讓模型截圖點按鈕。這篇要講清楚它為什麼能通、怎麼一步步接起來,以及哪幾個坑會讓你的 agent 安靜地失敗。

為什麼這條路走得通

三件事剛好湊在一起:

  1. Blender 的功能全都掛在 bpy 這個 Python API 底下。 GUI 只是 API 的一層皮——你在介面上點的每個按鈕,背後都有對應的 bpy.ops.* 或資料層操作。這代表「建模」在技術上等同於「寫 Python」。
  2. Blender 原生支援 headless。 --background 不開視窗、--python 直接餵一份腳本進去跑完就退出。這是給 render farm 用的老功能,agent 剛好白撿。
  3. Agent 最強的迴圈就是「寫程式 → 跑 → 讀結果 → 改程式」。 把 3D 建模轉譯成寫 Python,正好落在它最擅長的地帶。

反過來看 GUI 路線為什麼難:要 agent 用視覺點按 Blender 介面,每一步都得截圖、辨識面板、猜當下的選取狀態,錯一步很難回復,而且完全沒有 diff 可看。scene-as-code 則有版本控管、能重跑、能參數化、能交給另一個人接手。

這裡值得順帶對照另一條大家更熟的路線:Siddharth Ahuja 的 blender-mcpahujasid/blender-mcp)。它是一個 Blender 外掛加 MCP server,讓 Claude、Cursor 等客戶端透過 MCP 直接操作正在執行中的 Blender——能取得場景資訊、抓 viewport 截圖、拉 Poly Haven / Sketchfab 素材。這條路的優勢是「即時互動、看得到當下場景」;代價是要裝外掛、要開著 Blender、要維護連線,而且產出的操作不必然留下一份可重跑的腳本。

Simon 這條 CLI 路線則是另一個極端:零安裝、零連線、產物就是程式碼。

Coding agent 驅動 Blender 的執行迴圈:prompt → 寫 scene.py → headless 執行 → 產出 .blend 與 .png → agent 回讀 PNG 做視覺 QA → 改腳本重跑

運作原理:一行指令就是整條 pipeline

整套機制的核心只有這一行(Simon 在 TIL 裡建議你直接把它寫進 prompt,省下模型自己摸索的時間):

Use Blender like this: /Applications/Blender.app/Contents/MacOS/Blender --background --python scene.py

拆開看:

  • /Applications/Blender.app/Contents/MacOS/Blender —— macOS 上 .app 包裡的真正執行檔。這是 macOS 特有的細節,也是為什麼這篇 TIL 標題要掛 macOS:agent 常常只知道有 blender 這個指令,卻不知道 Homebrew Cask 裝的桌面版沒有把它放進 PATH
  • --background(等同 -b)—— 不開 GUI、不建視窗,跑完就退出。
  • --python scene.py —— 用 Blender 內建的那顆 Python 執行腳本。這點很關鍵:bpy 不能用系統 Python 跑,你的 agent 如果習慣性打 python scene.py 會直接 ModuleNotFoundError

然後迴圈是這樣轉的:

  1. Agent 把場景寫成 work/scene.py——幾何、材質、燈光、相機、render 設定全部程式化。
  2. 用上面那行指令跑掉。
  3. 腳本裡 bpy.ops.wm.save_as_mainfile().blend bpy.ops.render.render(write_still=True) 出圖。順序很重要,理由下面講。
  4. Agent 把產出的 PNG 讀回來看(這是整套流程裡最容易被跳過、但決定成敗的一步)。
  5. 發現輪胎浮空、遠景被地板蓋住、主體出框——回到第 1 步改腳本。

四個產物角色分得很乾淨:.py 是唯一真相(可 diff、可重跑)、.blend 是給人接手的(設計師能直接開來拉)、.png 是給 agent 回讀做視覺 QA 的、終端輸出則是給 agent 判斷有沒有炸掉的。

從 Simon 的實作裡抄得到的具體招式

他把整個實驗開源了,work/pelican_scene.pypelican_flair.pypelican_final.py 三個版本都在 repo 裡。讀完那幾支腳本,有幾個模式值得直接抄進你自己的 prompt。

招式一:叫 agent 先寫 helper 函式,不要硬幹 bpy.ops

pelican_scene.py 開頭定義了六個小工具:mat() 建材質、ell() 放橢球、rod() 在兩點之間拉圓柱、path() 用貝茲曲線做管狀物、torus() 做輪胎、mesh()from_pydata 直接造網格。之後整台腳踏車、整隻鵜鶘都是靠這六個函式組出來的。

其中 rod() 這招特別實用——把「從 A 點到 B 點拉一根管」變成一行:

def rod(name, a, b, r, material):
    a, b = Vector(a), Vector(b)
    d = b - a
    bpy.ops.mesh.primitive_cylinder_add(
        vertices=24, radius=r, depth=d.length, location=(a + b) / 2)
    o = bpy.context.object
    o.name = name
    o.rotation_euler = d.to_track_quat('Z', 'Y').to_euler()
    bevel = o.modifiers.new('Rounded edges', 'BEVEL')
    bevel.width = r * .28
    bevel.segments = 3
    o.modifiers.new('Weighted normals', 'WEIGHTED_NORMAL')
    return o

to_track_quat('Z','Y') 是把圓柱的 Z 軸對齊到方向向量的標準寫法。有了它,車架五根管就是五行 rod(...),輪輻是一個 28 次的 for loop。

可以照抄的 prompt 片段:

先在 work/ 建立一份 helpers.py,定義 mat / ell / rod / path / torus 這幾個 primitive helper,之後所有場景腳本都 import 它。不要在主腳本裡重複貼 bpy.ops.mesh.primitive_*_add 的樣板碼。

招式二:render 設定當成 checklist 交給 agent

Simon 讓 Codex 產出的 skill 檔裡,把「收尾設定」寫成一段固定模板:

scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.samples = 64
scene.cycles.use_denoising = True
scene.render.resolution_x = 1600
scene.render.resolution_y = 1200
scene.render.resolution_percentage = 100
scene.view_settings.view_transform = 'AgX'
scene.render.image_settings.file_format = 'PNG'
scene.render.filepath = str(output_dir / 'scene.png')
bpy.ops.wm.save_as_mainfile(filepath=str(output_dir / 'scene.blend'))
bpy.ops.render.render(write_still=True)

裡面有兩個判斷值得記住。第一,samples 的建議值:skill 裡寫預覽用 32–48、要出成品用 64–96,並開 denoising。Simon 的三個版本實際上就是 48 → 96 遞增(最終版 pelican_final.py 是 2000×1600、96 samples)。第二,view_transform = 'AgX'——這是 Blender 4.0 之後的預設色調映射,比舊的 Filmic 更不容易把高光燒白;agent 如果沿用網路上舊教學可能會設成 Filmic 或 Standard,畫面就會偏。

還有一句 skill 裡明講的提醒:「Do not assume GPU acceleration is configured.」 Cycles 預設走 CPU,你的 render 時間會比想像中長,這也是為什麼那三輪迭代要花 2–6 分鐘。

招式三:強制 agent 回讀渲染圖

這是整篇最重要的一招。Simon 讓 Codex 產出的 skill 裡有一句幾乎可以裱框的話:

A successfully saved render is not visual QA.

(render 成功存檔,不等於做過視覺檢查。)

Skill 裡列出的檢查清單非常具體,你可以直接複製進自己的 AGENTS.mdCLAUDE.md

  • 剪影對不對(smooth shading 救不了面數不夠的多邊形輪廓)
  • 手有沒有真的握到握把、腳有沒有踩到踏板
  • 有沒有零件浮空
  • 主體有沒有被畫面裁到
  • 陰影合不合理
  • 背景細節到底有沒有出現在畫面裡(加了不等於看得到)

同一份 skill 還記了幾個他們真的踩過的坑:舊的攝影棚地板沒刪掉,結果把新加的沙灘和海洋整個蓋住;共面重疊的表面渲出黑帶(就是 z-fighting);正交相機配無限延伸的地平面根本不會有自然地平線,得另外放一片遠景天空背板才會有一條齊的水平線。

招式四:把「怎麼開 Blender」沉澱成 skill

Simon 最後一步是叫 Codex 用它內建的 skill-creating skill,把這次學到的東西打包:

Create a quick skill that describes how to use the currently installed /Application/Blender based on what you learned

產出的 SKILL.md frontmatter 長這樣:

---
name: blender-local
description: Build, edit, and render 3D scenes with the locally installed Blender on this Mac. Use when the user requests Blender work or an editable Blender scene.
---

之後他就用 Use your Blender Local skill to build this scene (attached image) 這種一句話 prompt 繼續玩。

這份 skill 的內容編排本身就是範本:已驗證的執行檔絕對路徑(skill 裡甚至特別註記是複數的 Applications,不是 /Application/Blender——因為第一次 prompt 打錯了)、工作流程(腳本放 work/、產物放交付目錄、要改舊場景就 bpy.ops.wm.open_mainfile(filepath=...) 而不是把舊腳本切一段出來跑)、已知的執行問題視覺教訓

這比「寫一份泛用的 Blender 教學」有價值得多,因為它記的是這台機器、這個版本、這次踩到的事

幾個會讓 agent 安靜失敗的坑

CLI 腳本路線與 MCP 外掛路線的對照:控制介面、產物、可重現性、版本控管與適用情境

坑一:Python 例外了,Blender 還是回傳 exit code 0

這是最陰的一個。Blender 官方手冊對 --python-exit-code 的說明是:設定一個 0–255 的 exit code,在 Python 拋出例外時用它退出(僅適用於命令列執行的腳本),設為零則關閉此功能。換句話說——預設是關的

意思是:你的 agent 跑了腳本,腳本在第 40 行就炸了,Blender 印了 traceback 然後正常退出、exit code 0。Agent 一看回傳成功,就跑去回報「場景已完成」。這在 Blender 的 issue tracker 上是個老問題(#17647、#82494 都在談這件事),而且 issue 裡也提到 --python-exit-code 在某些情境(例如 unregister 階段的例外)仍然可能吞掉錯誤。

所以請把這行寫進你的 skill 或 AGENTS.md

/Applications/Blender.app/Contents/MacOS/Blender \
  --background \
  --python-exit-code 1 \
  --python work/scene.py

並且加一條規則:agent 必須確認 .png.blend 兩個檔案真的被寫出來、mtime 是新的,才算完成。 光看 exit code 不夠。

坑二:引數是按順序執行的

Blender 手冊明說引數依給定順序執行。這代表 -o(輸出路徑)、-E(引擎)、-f / -a(觸發 render)之間的順序不能亂排——設定類的旗標必須排在觸發 render 的旗標之前,否則設定不會生效。同樣地,要載入既有 .blend 檔,檔名要放在最前面:

blender scene.blend --background --python-exit-code 1 --python tweak.py

如果要把參數傳給你的腳本,用 -- 分隔,之後的東西 Blender 一律不解析、原樣丟進 sys.argv

blender -b --python-exit-code 1 --python render.py -- --samples 96 --out /tmp/out

腳本裡這樣撿:

import sys
argv = sys.argv[sys.argv.index('--') + 1:] if '--' in sys.argv else []

這招對 agent 特別有用——腳本寫一次,畫質預覽和最終出圖用同一份程式碼、不同參數,agent 不會為了改 samples 而去改壞別的東西。

坑三:sandbox 會讓 Blender 直接 segfault

Simon 的 skill 裡記了一筆很具體的環境問題:這個專案第一次在 sandbox 裡啟動 Blender 時,還沒跑到腳本就以 exit code 139 退出(139 = 128 + 11,SIGSEGV),並在系統暫存目錄留下 blender.crash.txt。改用「已核可的非 sandbox 執行途徑」重試就成功了。同時出現的 USD Arch_ValidateAssumptions 警告,skill 裡誠實註明「並未證實是根因」。

這件事對用 Claude Code / Codex 的人很實際:這類 agent 預設把指令跑在受限環境裡,而 Blender 啟動時會碰 GPU、audio、檔案系統一堆東西,很容易在 sandbox 下掛掉。如果你遇到「還沒印任何腳本輸出就 139」,先懷疑 sandbox,不要懷疑腳本。

(順帶一提,Blender 自己的 issue #126807 也有一個「用 bpy 模組跑 Cycles,渲染成功但 exit status 永遠是 139」的案例。exit 139 在 Blender 世界不算罕見,別讓 agent 拿它當「腳本有 bug」的證據。)

坑四:API 正在變

Simon 的 skill 記錄他那台機器上是 Blender 5.1.2(2026 年 9 月),並註明 Material.use_nodesWorld.use_nodes 已經噴 deprecation 警告、仍可運作,但預期在 Blender 6 會改

版本本身也在跑:目前 Blender 官方手冊掛的是 5.2 LTS,PyPI 上的 bpy 套件最新是 5.2.1(2026-08-25 發佈)、只支援 Python 3.13。這代表兩件事:一,模型訓練資料裡的 Blender API 寫法很可能過時;二,你應該讓 agent 每次開工前先跑一次版本檢查,而不是相信它記得的 API:

/Applications/Blender.app/Contents/MacOS/Blender --version

想出影片的話

Simon 在 TIL 開頭就提到模型「也能出影片——渲染一連串圖片再用 ffmpeg 合起來」。他的 repo 裡沒有影片範例,所以以下是這條路的標準做法,不是他實測過的流程:

在腳本裡設好 scene.frame_start / frame_end 和動畫 keyframe,然後:

blender -b scene.blend \
  -o /tmp/frames/f_#### \
  -F PNG \
  -a

#### 會被換成補零的影格編號。接著:

ffmpeg -framerate 24 -i /tmp/frames/f_%04d.png \
  -c:v libx264 -pix_fmt yuv420p -crf 18 out.mp4

為什麼不讓 Blender 直接輸出影片?因為分成兩段對 agent 友善得多:渲染中斷可以只補缺的影格、agent 可以抽幾張 frame 回讀做 QA、換 codec 不用重渲。這條原則跟前面「先存 .blend 再 render」是同一個思路——把長時間、易失敗的步驟切開,讓每一段都可以單獨重跑。

macOS 以外呢

TIL 標題掛 macOS,是因為那條 .app 執行檔路徑是 macOS 專屬的麻煩。換平台就換路徑:

  • Linux:套件管理裝的通常 blender 就在 PATH 上;Snap / Flatpak 或官方 tarball 則要指到解壓目錄下的 blender
  • Windows:預設在 C:\Program Files\Blender Foundation\Blender <版本>\blender.exe
  • 完全不裝桌面版pip install bpy(現在是 5.2.1)把 Blender 當成 Python 模組用,官方 wheel 涵蓋 macOS ARM64、Linux x86-64(glibc 2.28+)、Windows x86-64 與 ARM64。這條路對 CI 和容器最乾淨——不用 --background --python,直接 import bpy 就好,代價是綁死 Python 3.13、而且沒有 GUI 可以打開來檢查。

Agent 常犯的錯是假設 blenderPATH 上。在你的 skill 裡寫死已驗證的絕對路徑,這就是 Simon 的 skill 第一段在做的事。

什麼時候該用、什麼時候別用

適合的:

  • 程式化、參數化的資產——同一個場景換 20 種顏色 / 尺寸 / 角度,寫一次腳本跑 20 次。
  • 技術示意圖與封面圖——需要精確的幾何關係(等角視圖的架構圖、機構爆炸圖、3D 資料視覺化)。
  • 需要可版控、可交接的產物——.py 進 git,.blend 給設計師接手。
  • 需要在 CI 裡重跑的東西——文件裡的示意圖跟著程式版本自動重新渲染。

不適合的:

  • 要「好看」而不是要「正確」的圖。Simon 那三張鵜鶘很可愛,但那是三輪迭代 + 一個非常會寫 code 的模型的結果,而且風格明顯是「pastel 玩具感」——這正是程式化建模最容易到達的美學區間。要寫實材質、要人臉、要有攝影感,擴散模型類的圖像生成幾乎一定更快更好。
  • 角色動畫、布料 / 流體模擬、雕刻。這些領域的迭代成本高、參數空間大,靠盲寫腳本收斂很慢。
  • 趕時間的一次性圖。前面說了,CPU render 一輪就是幾分鐘。

一句話總結 trade-off:這條路買的是「可控與可重現」,不是「省時間」也不是「更漂亮」。

對工程團隊的意義

如果你要把這件事變成團隊能用的能力,我會這樣排:

  1. 把 Blender 當成另一個 build target,不是設計工具。 場景腳本放進 repo、產物寫進 dist/、能在 CI 跑。這樣定位之後,所有工程慣例(review、版本、重跑)都自動適用。
  2. 第一天就寫 skill,不要等第三次才寫。 內容照 Simon 那份的骨架:已驗證的絕對路徑與版本、執行指令(含 --python-exit-code 1)、產物放哪、已知的環境坑、視覺 QA 檢查清單。這份檔案的價值在於它記的是你這台機器上的事實
  3. 把「回讀渲染圖」寫成硬規則。 沒有這一步,你拿到的就是一堆技術上成功、視覺上災難的 PNG。
  4. 成本結構要跟團隊講清楚。 這件事貴在 CPU 時間,不在 token。一輪 2–6 分鐘(Simon 回報,CPU Cycles、無 GPU 加速)意味著 agent 會有很長的等待窗口——別讓它在等待期間重複發起渲染,Simon 的 skill 就明確寫了「若執行回傳 session ID,就輪詢那個 session,不要另外再開一個 render」。
  5. 先挑一個真實的小需求試。 不要從「做一支產品宣傳片」開始。從「把我們架構圖的那顆立方體做成等角視圖 3D 版,換三種配色」這種規模開始,你會在半小時內知道這條路對你的團隊值不值得。

來源

整理:DataAgent · Coding Agent 實戰教學

發表迴響

%d 位部落客按了讚: