目录

Vision-as-Inverse-Graphics Agent via Interleaved Multimodal Reasoning


作者Shaofeng Yin, Jiaxin Ge, Zora Zhiruo Wang, Chenyang Wang, Xiuyu Li, Michael J. Black, Trevor Darrell, Angjoo Kanazawa, Haiwen Feng
机构UC Berkeley; Carnegie Mellon University; Max Planck Institute for Intelligent Systems; Impossible, Inc.
版本arXiv 2601.11109 (v1 2026-01-16, v3 2026-04-06)
链接https://arxiv.org/abs/2601.11109
项目VIGA-website · github.com/Fugtemypt123/VIGA

把 Claude Code 式的 coding agent 搬进 Blender:一个 VLM 写 Blender Python 脚本 → 渲染 → 另一个 VLM 拿渲染图跟参考图比(可以自己挪相机、隐藏物体、跳关键帧去看)→ 写一段文字修改意见 → 再改脚本,循环直到像为止。相比 BlenderAlchemy 这类「迭代编辑」前作,多的是只读的观察工具和只保留最近 L 轮的滑动窗口上下文。完全 training-free。

Figure 6
图 6:单张参考图(照片、手绘草图)→ Blender 场景。中间是对齐参考视角的渲染,右边是换视角的渲染,证明得到的是真正的 3D 场景而不是 2D 贴图。注意寿司这种复杂几何体是 get_better_assets 调外部 3D 生成模型拿到的 mesh,agent 负责的是摆放、材质、光照和相机。

术语速查

论文用词在本文里具体是什么
inverse graphics输入一张图,输出能在图形引擎里重新渲染出这张图的程序(这里是 Blender Python / python-pptx 脚本)。
target \(s_g^*\)参考图片(照片 / 草图 / 风格迁移过的图 / 带箭头提示的图)+ 可选文字指令,例如「把篮球移到 goal state 的位置」。
program \(p_t\)第 t 轮的完整 Blender Python 脚本:建/导入物体、设位置、材质、灯、相机。每轮都重写整份代码(同时附一个 diff)。
state \(s_t\)执行 \(p_t\) 后的 Blender 场景及其渲染图。
agent \(\mathcal{A}\)现成的 VLM(GPT-4o / GPT-5 / Claude-Sonnet-4 / Gemini-2.5-Pro / Qwen3-VL-8B),不训练,靠 system prompt + tool calls 驱动。实际分成两个会话:Generator(写代码)和 Verifier(只读检查)。
skill library一组 JSON-schema 工具:execute_code、set_camera、investigate、get_scene_info、set_visibility、set_keyframe、get_better_assets、undo_action、end_process 等,包装底层 bpy 调用。
feedback \(f_t\)Verifier 输出的一段自然语言,例如「篮球卡进桌子里了,应该再高一点」。
memory \(M_t\)聊天上下文里最近 L 轮的 (plan, code diff, 完整代码, 渲染图, feedback)。更早的直接丢掉。定性实验 L = 12。
best-of-N每轮并行生成 N 个候选修改,用渲染图与目标图的 CLIP 相似度挑最好的进入下一轮。
4DBlender 物理模拟(刚体、碎裂)+ 关键帧。Verifier 用 set_keyframe 跳到不同时间点看动画。

研究动机

核心方法

Figure 2
图 2:VIGA 主循环(以「把篮球移到目标位置」为例)。Memory 里保留了 ball z = 0.8 → 0.7 → 0.75 的历史,agent 靠比较前几次的参数和对应渲染来二分逼近;Verifier 发现看不清时会调 set_camera 换视角。
flowchart LR
  T["Target image"] --> G["Generator VLM"]
  M["Memory last L"] --> G
  G -->|"execute_code"| B["Blender render"]
  B --> V["Verifier VLM"]
  T --> V
  V -->|"set_camera, investigate"| B
  V -->|"text feedback"| M
  G -->|"plan + code"| M
  G -->|"end_process"| E["Final program"]
          
drag to pan · scroll to zoom
数据流:Generator 读目标图和最近 L 轮记忆,写代码并执行;渲染结果交给 Verifier,Verifier 用只读工具反复观察场景,最后产出文字反馈写回记忆。Generator 认为够像时调 end_process 结束。

1. Interleaved 循环:plan → code → render → observe → feedback

Algorithm 1 每一轮分四个阶段:

  1. Plan:\(\tau^{plan}_t = \mathcal{A}(s_g^*, M_t)\)。如果计划里有 end_process 就结束。
  2. Code:\(p_t = \mathcal{A}(s_g^*, M_t, \tau^{plan}_t)\),通过 execute_code 提交(含 thought、code_diff、完整 code 三个字段)。
  3. Render:\(s_t = \text{exec}(p_t)\)。出错时返回报错信息,成功时返回渲染图——要求代码里自己放相机。
  4. Observe + Feedback:Verifier 先用工具探索得到 \(\tau^{obs}_t\),再输出 \(f_t = \mathcal{A}(s_g^*, s_t, \tau^{obs}_t, M_t)\)。
  5. Memory:\(M_{t+1} = \text{Tail}_L(M_t \cup \{p_t, f_t\})\)。

两个角色共用同一个 VLM,只是 system prompt 和可用工具不同:Generator 拿「修改型」工具,Verifier 只拿「只读型」工具。每次回复必须恰好一个 tool call 加一段推理。

Figure 3
图 3:Verifier 的主动观察。在杂乱场景里先找不到角色 → Focus('character') → Zoom('in') → 发现肚子比目标大 → 建议调小 belly 参数。
Figure 4
图 4:细粒度视觉差异 → 具体代码参数。幻灯片里「图片挡住了文字」→ bbox 改 1;房间里「主灯应从黄变白」→ light color (1,1,0) → (1,1,1);角色「嘴应该笑」→ shape key smile 0 → 1。

直观理解:VLM 本身做不好「看图报坐标」,但很擅长「看两张图说哪里不一样、往哪个方向改」。VIGA 把精确数值的问题转化成一串「比较 + 方向」的判断,让渲染器去负责精确的投影。

2. 滑动窗口记忆:只留最近 L 轮

Memory 是多模态轨迹(plan、代码、渲染图、反馈交替)。保留历史的作用是让 agent 能比较自己之前的尝试(0.8 太高、0.7 太低 → 取 0.75),否则会在两个错误状态之间来回振荡。但全部保留会导致 context rot:图片越堆越多,模型推理变差。所以只保留最近 L 轮。

作者论证截断是「无损」的:因为每轮的 \(p_t\) 是完整代码,本身就编码了之前所有成功的编辑;老的推理过程是多余的。(这个论证只对「场景状态」成立,对「哪些试过不行」这种负面经验并不无损。)

Figure 5
图 5:唯一的 memory 消融(定性)。有滑动窗口时逐步搭出圣诞树、沙发、壁炉;没有窗口(全量上下文)时后期把之前建好的树丢了,空间关系也乱了。

3. Skill library:把 bpy 压缩成语义级动作

直接让 VLM 写裸 bpy 动作空间太大、容易幻觉 API。VIGA 把它包装成两类工具,观察和修改严格分开:

类别SkillAPI作用
State Observation(只读)Spatial Navigationset_camera, investigate换视角、绕开遮挡
Temporal Inspectionset_keyframe跳到 4D 时间轴某一帧
Structural Queryget_scene_info, set_visibility查物体属性、临时隐藏物体
Diagnostic Renderinginitialize_view渲染标准视角、算目标 bounding box
State Modification(写)Asset Instantiationinit_scene, get_better_assets调外部模块(SAM-3D、Meshy、Tripo 一类)拿高质量 mesh
State Executionexecute_code执行完整脚本,持久修改场景
Trajectory Controlundo_action, end_process回滚 / 结束
execute_code 的 schema(附录 D 节选)
{
  "name": "execute_code",
  "description": "Execute blender python code and trigger verifier evaluation. Returns either (1) on error: detailed error information; or (2) on success: a clear render (you must add a camera in your code) and further modification suggestions from a separate verifier agent.",
  "parameters": {
    "thought":   "step-by-step reasoning about what code to write next",
    "code_diff": "minimal line-level edits: '-: [lines to remove]' then '+: [lines to add]'",
    "code":      "the COMPLETE updated Blender Python code after applying code_diff"
  }
}

要求同时输出 diff 和完整代码:diff 让模型先想清楚改哪几行,完整代码保证每轮的状态自包含(这也是滑动窗口能「无损」截断的前提)。

4. 同一个循环跨 2D / 3D / 4D

换执行引擎即可:Blender 做 3D 重建和编辑;Blender 物理引擎 + 关键帧做 4D(扔球撞水果、打碎镜子、地震);python-pptx 做幻灯片。Prompt 只改几个关键词(2D → 3D)。

Figure 8
图 8:单张图 + 文字指令 → 物理模拟。水果、桌子等由 init_scene 调 SAM-3D 拿 mesh,镜子由基本几何体程序化生成;agent 负责设质量、碰撞体、初速度等物理参数。物理正确性由 Blender 物理引擎保证,而不是生成模型。
Figure 7
图 7:文字描述 → PowerPoint。同一循环,执行器换成 python-pptx。

5. 最关键的一句话

让 VLM 只做它擅长的「比较两张图、说往哪改」,把精确投影交给渲染器、把状态交给完整代码、把观察交给可以随意挪相机的只读工具,然后循环。

主要实验结果

BlenderBench(VLM Score ↑)

GPT-4o 作为底座。Task 1 上 VIGA best-of-1(1.44)其实低于 BlenderAlchemy(1.75),要 best-of-4 才拉开到 3.25;Task 3 的提升最稳定(0.67 → 1.53)——这正是需要跨步一致性、最依赖记忆的任务。
Qwen3-VL-8B 作为底座。小模型下 VIGA 的增益更大(best-of-1 平均 +312% vs BlenderAlchemy);BlenderAlchemy 在 Task 3 甚至比 one-shot 更差(0.64 < 1.25),说明无记忆的迭代会把之前的修改覆盖掉。
BlenderBench 完整表(Table 2)
ModelSettingT1 PL↓T1 N-CLIP↓T1 VLM↑T2 PL↓T2 N-CLIP↓T2 VLM↑T3 PL↓T3 N-CLIP↓T3 VLM↑Impr.%
GPT-4oOne-Shot48.1664.170.587.367.122.7530.1438.690.25-
BlenderAlchemy bo110.6217.681.756.137.713.0819.6026.100.6767.56
VIGA bo18.5618.191.445.114.333.5814.5117.911.53113.96
BlenderAlchemy bo414.5019.571.751.952.473.5320.6225.790.5677.48
VIGA bo45.476.103.252.943.503.8312.6222.841.61159.19
Qwen3-VL-8BOne-Shot60.8278.160.2833.1437.511.6122.8122.981.25-
BlenderAlchemy bo125.6137.930.3610.6913.922.6430.4523.910.6427.36
VIGA bo110.5417.271.313.853.343.3311.356.862.25112.79
BlenderAlchemy bo411.5717.581.195.384.642.9423.6215.670.9382.24
VIGA bo48.8015.671.385.023.863.089.086.942.02112.87

注意 GPT-4o 的 Task 2 best-of-4:BlenderAlchemy 的 PL / N-CLIP(1.95 / 2.47)明显好于 VIGA(2.94 / 3.50),VIGA 只在 VLM Score 上略胜。

Figure 9
图 9:BlenderBench 三类任务示例。Task 1 要把相机从房间外挪进角落;Task 2 视角固定,逐步改灯光强度、角色肚子大小;Task 3 先找视角再搬柜子、搬盆栽。

BlenderGym 与 SlideBench

BenchmarkModelOne-ShotVIGA说明
BlenderGymGPT-4o bo4Impr. 基准+48.86%vs BlenderAlchemy bo4 的 +27.63%;material N-CLIP 12.20 → 7.63
BlenderGymQwen3-8B bo4Impr. 基准+42.88%vs BlenderAlchemy bo4 的 +23.23%;全设置平均 +35.32%
SlideBenchGPT-4o55.858.3Overall +4.5%
SlideBenchClaude-3.560.762.2Overall +2.5%;执行成功率反而 0.93 → 0.90
SlideBenchGemini-2.541.448.9Overall +18.1%
SlideBenchQwen3-8B6.032.8Overall +446.7%;执行成功率 0.10 → 0.54,本质是「报错后能改代码」

SlideBench 宣传的「平均 +117.17%」几乎完全来自 Qwen 那一行(+446.7%);强模型上的增益只有 2.5–18%。对强模型而言,PPT 一次就能写对,迭代只修了少量执行错误。

局限与展望