Code-as-Room: Generating 3D Rooms from Top-Down View Images via Agentic Code Synthesis
Paper: arXiv:2605.18451 Code: YxuanAr/Code-as-Room Code reference:
main@ffd266c6(2026-05-22)
1. Motivation (研究动机)
这篇论文要解决的是一个非常具体的 3D 场景生成问题:给定一张 top-down room image(俯视图、草图、layout-like image 或平面布局参考),自动生成一个完整、可渲染、可编辑的 Blender 3D room 程序。作者把目标设为“从图像到 Blender code”,而不是只生成一张室内效果图,因为 code 表示可以继续编辑、换视角渲染、检查几何关系,也更适合 VR、游戏、室内设计和 Embodied AI 的下游使用。
当前方法的瓶颈主要有三类。第一,传统 procedural / rule-based / optimization-based indoor scene synthesis 依赖手工规则、固定类别和设计约束,难以覆盖真实室内空间里复杂的物体组合、墙面元素、支撑关系和用户偏好。第二,text-to-scene 或 text-conditioned MLLM 方法虽然可以输出 JSON / scene graph / object attributes,但文本很难精确描述物体数量、位置、朝向、支撑面和区域功能,因此生成的 3D room 往往与用户心中的空间布局不一致。第三,已有 image-conditioned agent(论文重点对比 VIGA)在 perspective image reconstruction 上可行,但直接迁移到 top-down holistic room generation 时会丢失细粒度空间细节,并且 generator–critic loop 容易陷入无限循环,导致生成不稳定、Blender code 不可靠。
作者的关键观察是:真实设计流程里,top-down layout / sketch / floor-plan-like image 本身就是很强的空间先验。它比文字更直接地编码了房间边界、功能区域、家具相对位置、朝向、墙面/门窗位置和整体比例。如果能把这个空间先验拆解成可执行的阶段化 code synthesis 流程,就可以同时利用 MLLM 的视觉理解、空间推理和代码生成能力,又避免“单次生成整屋代码”带来的上下文遗忘和循环失控。
Figure 1 解读:这张 teaser 展示了任务形式:输入可以是多种 top-down room images,输出是 Blender 中可交互的 3D scenes。它强调 Code-as-Room 的核心不是做 2D image translation,而是让 MLLM 通过结构化执行 harness 生成可执行、可编辑的 Blender scene code。
2. Idea (核心思想)
核心思想是把 3D room generation 重新表述为 top-down image-guided agentic code synthesis:图像提供全局空间先验,MLLM 负责分阶段理解、生成和修复 Blender code,cross-stage memory 负责把前面阶段的结构化输出保留下来,避免长链路 agent workflow 中的 context forgetting。
这与 VIGA 这类 analysis-by-synthesis agent 的根本区别在于:Code-as-Room 不让一个 agent 在同一个 loop 里“看图—写整屋代码—critic—再写整屋代码”,而是把问题拆成五个语义阶段:image-based scene structuring、layout code generation、layout-grounded object profiling、object-level code generation、interior decoration code generation。每个阶段只处理一个相对清晰的中间表示,并把结果写入 typed memory entry,下游阶段按需读取 memory view。
这种设计的直觉是:俯视图到完整 3D room 的难点不在某一个模型能不能写 Blender API,而在“空间一致性”和“细节可控性”必须逐层锁定。先固定房间边界、主要家具和支撑关系,再补局部几何、材质、纹理和光照,可以减少后续阶段推翻前面布局的概率;render-and-compare visual feedback 只修正 layout-level 错误,也比让 agent 在最终渲染阶段大幅重写场景更稳定。
3. Method (方法)
3.1 Overall framework:从俯视图到 Blender scene code
给定房间级 top-down image ,目标是生成可执行 Blender code ,其中 code 同时定义房间结构、物体位置、物体几何、材质和光照。论文把整个系统写成: 其中 是 Code-as-Room 的 VLM-agent harness。直接从 一次性生成完整 很困难,所以作者采用 coarse-to-fine decomposition。粗阶段先构建 scene understanding 和 layout program: 细阶段再基于 layout 进行 object profiling 和最终 code generation: 这里 是所有阶段共享的 cross-stage memory。这个分解把全局空间对齐和局部细节合成分开:粗阶段锁定 room structure、major object placement 和 layout relations;细阶段只在既定 pose/scale 上增加 editable geometry、appearance 和 rendering code。
Figure 2 解读:pipeline 图把系统分成五个 phase。左侧输入图像先经过 scene classifier / spatial semantic analysis / scene graph construction,形成 coarse understanding;中间 layout code generation 使用 visual feedback loop 逐轮渲染、比较和修正;后续 object-level stages 把 bounding-box proxy 替换成由 primitive parts 组成的对象,并为小物体、材质、纹理和光照生成代码。图中的 memory arrows 是关键:每个阶段将 typed artifact 写入 memory,下游只读取需要的 memory view,而不是依赖一个不断膨胀的 prompt。
3.2 Cross-stage memory:让长链路 agent 不遗忘
每个阶段 产生 typed artifact: 其中 是阶段编号, 是 artifact 类型, 是阶段输出, 是 metadata。memory 更新为: 下游阶段不是无差别读取全部历史,而是读取预定义 memory view。这样做有两个作用:一是保留早期视觉解析出的 object ids、parent relations、wall anchors、minor-object sidecar,避免后面生成 geometry / material 时忘记;二是减少 prompt noise,降低 agent 为了“补全上下文”而 hallucinate 新对象或新关系的概率。
released code 中,agent_utils/memory.py 定义 MemoryEntry、Memory 和 MemoryAwareAgent,实际把 memory 写成每个 run directory 下的 agent_memory.jsonl。这对应论文中的 ,但实现层面还提供 get_latest、get_by_stage、get_context_for_stage、query_by_semantic_tags 等检索函数。
3.3 Image-based scene structuring:先把图像变成可约束的 scene state
前两个 stage 负责把输入图像 转成结构化 scene state。
Stage 1: spatial semantic analysis
Stage 1 输出 schema-constrained description : 包括 functional zones、object hierarchies、architectural elements。每个 object 被赋予 identifier、category、placement type 和 parent;walls、doors、windows、openings、built-in structures 被保留为固定空间参考。论文特别提到 perimeter-aware prompt:它扫描墙、角、开口和 coarse grid,以恢复 peripheral / wall-mounted objects。这一步如果缺失,后续 layout stage 很容易只放出中心家具,漏掉贴墙柜、门窗、墙面装饰等约束物。
Stage 2: object-centric scene graph construction
Stage 2 读取 ,先构造 deterministic skeleton:
其中 是建筑元素, 是 layout-defining objects, 是 hierarchy-derived relations, 是稍后处理的小物体 sidecar。VLM 只补全 attributes、geometry hints 和 forward relations,不允许随意改写 skeleton。最后过滤非法边、添加 inverse relations 和 wall/corner anchor relations:
released code 中,agent_utils/stage2/run_stage2.py 的 _build_node_skeleton、_derive_wall_edges、_derive_corner_edges、_make_inverse_edge 和 _merge_skeleton_with_llm 体现了“先 deterministic skeleton、再让 LLM 补属性/关系”的策略。这是论文方法中比单纯 prompting 更稳定的部分。
3.4 Layout code generation:用可渲染 proxy 锁定空间关系
Layout stage 生成粗布局程序 。对象先以 Blender 中的 named bounding-box proxies 实例化,包含 approximate position、scale 和 orientation;详细几何、材质、光照和 tiny objects 推迟到后续 stage。因为每个 placement 都是 primitive-constructor call, 可以被渲染成 top-down image,也可以被后续 stage 解析。
Stage 3: major layout with visual feedback
Stage 3 通过 render–critique–revise loop 修正 major object layout。初始化:
第 轮先渲染当前 code,再让 VLM critic 比较输入图和渲染图:
critic 输出 textual feedback 和 layout quality score ,分数覆盖 object coverage、overlap、boundary consistency 和 spatial relation correctness。由于 critic 可能建议不受支持的建筑改动,系统先做 sanitize:
停止条件是 或达到最大迭代 ;论文实验和 released config 都使用 。released code 的 example/pipeline_config.example.json 中 max_iter=5、target=0.85;run_pipeline.py 的 UnifiedPipeline.run_stage3 调用 Stage3 runner,并在每个 run directory 保存 stage 输出。
Stage 4: wall objects and selected minor placeholders
Stage 4 冻结 major layout,再追加 wall-mounted objects 和 coarse-scale visible minor objects。wall-mounted objects 会根据 scene graph 中的 semantic anchors 对齐到推断的 wall planes;minor sidecar 中只保留在 coarse layout 尺度可见且不是 surface-bound 的对象: 这包括 rugs、floor lamps、plants 和 large decorations;books、cups、small tabletop items 等 tiny surface-bound objects 被推迟到 fine-grained placement。设计上,Stage 4 的作用是补足会影响空间占用和布局理解的对象,而不让早期布局阶段被小物体细节淹没。
3.5 Object-level code generation:从 proxy 到可编辑局部几何
Stage 5: layout-grounded object description
Stage 5 解析 中已经放置的对象,保留每个 object 的 identifier、category、pose 和 size,再结合输入图与 memory 生成 fine-grained object descriptions 。描述包括 color、material、function、structure、style,以及全局 room-style JSON。它不应改变物体放置,只补足“这个椅子/桌子/柜子长什么样、由哪些语义部件构成、材质风格是什么”。
Stage 6: object geometry replacement
Stage 6 对每个 placed object 预测 semantic 3D primitive decomposition: 每个 part 指定 primitive type、semantic part name、local size、offset 和 rotation。因为 parts 定义在原 proxy 的 local frame 中,生成对象继承 coarse layout pose,从而避免 geometry 细化时破坏整体布局。代码替换写作: 同一映射还会保存为 geometry dictionary,供后续 surface discovery 和 material assignment 使用。
Tiny objects: procedural placeholder + retrieval
对几何细节复杂的小物体,论文采用 hybrid procedural-and-retrieval。先创建简单几何 placeholder 来保留位置和占用区域,再从 asset library 中检索匹配资产:
matching score 同时考虑语义相关性和尺寸兼容性;选中的 asset 被 scale / align 到 placeholder,保持支撑面和 footprint。released repo 目前的 README 标注:3D assets retrieval checkpoint 尚未发布;codebase 中 Stage 7–9 已有 small-object placement / description / geometry 的 optional extension,但 example/pipeline_config.example.json 默认 detail_small_objects=false,只有打开 --detail-small-objects 才运行 Stage 8 和 Stage 9。
3.6 Interior decoration code generation:材质、纹理、光照和 post-hoc correction
布局和对象几何固定后,系统通过 geometry-preserving rewriting 完成外观与渲染: Stage 8/10(论文编号/代码编号存在差异,见下文)进行 part-level PBR material assignment:输入 part dictionary、fine-grained descriptions 和 global room style,输出 material type、linear-RGB base color、roughness、metallic、specular strength,并注入 Blender script。Glass / mirror-like surfaces 通过 material type 或 part-name keywords 触发 shader overrides;floors / walls 使用 procedural shader nodes。
Texture stage 为 floors、walls、rugs、paintings、posters、decorative panels 合成 texture maps,并把 image-texture nodes 注入 material graph。Render stage 根据输入图和当前 scene 推断 overall lighting style,包括 dominant illumination direction、window-driven natural light、artificial light sources 和 ambient intensity,再生成 Blender light objects 和 Cycles render settings。
最终 post-hoc correction 修复 missing material assignments、invalid texture paths、unreasonable light intensities、incomplete camera coverage 和 geometric artifacts。对边界或碰撞违规的可移动对象,论文写作局部投影搜索: subject to 这里 是生成位置, 是局部网格邻域, 是房间边界,碰撞约束只对 nearby non-parent objects 应用。实践中用 deterministic local search、boundary clamping 和 stacking offsets 实现。
论文公式与 released code 实现差异
论文把五个 phase 展开成 Stage 1–10,并在文字中称 material / texture / lighting 分别是 Stage 8、Stage 9、Stage 10;released code 的 README 和 run_pipeline.py 则是 Stage 0–12:Stage 0 scene classification,Stage 7 surface-based small-object placement,Stage 8/9 是 optional detailed small-object extension,Stage 10 per-part PBR material,Stage 11 real texture generation,Stage 12 lighting/render settings。因此本文笔记中的方法编号以论文叙述为主,但代码映射以 main@ffd266c6 的实际 stage 编号为准。
另一个差异是 retrieval assets:论文描述了 asset library 和 retrieval-based replacement,但 README 的 Release Plan 显示 “3D assets retrieval checkpoint release” 尚未完成;当前 release 更偏向 code-only geometry、optional small-object geometry 和 texture/render generation。最后,论文 benchmark 是内部/人工修正的 41-scene benchmark;README 标注 benchmark release 仍在计划中,因此 released repo 不能直接复现论文完整 benchmark 数字。
3.7 Pseudocode(基于 released code 的实现抽象)
from pathlib import Path
class AgentMemory:
def __init__(self, run_dir: Path):
self.path = run_dir / "agent_memory.jsonl"
self.entries = []
def add(self, stage: str, entry_type: str, content: dict, metadata: dict | None = None):
self.entries.append({"stage": stage, "type": entry_type, "content": content, "metadata": metadata or {}})
self.path.write_text("\n".join(serialize(e) for e in self.entries), encoding="utf-8")
def latest(self, stage: str, entry_type: str = "result") -> dict:
for entry in reversed(self.entries):
if entry["stage"] == stage and entry["type"] == entry_type:
return entry["content"]
raise KeyError((stage, entry_type))def run_code_as_room(image_path, config):
run_dir = make_run_dir(config.output_dir, image_path)
memory = AgentMemory(run_dir)
scene_type = classify_scene(image_path, config.scene_classify_model)
memory.add("meta", "scene_type", scene_type)
d1 = stage1_spatial_semantic_analysis(image_path, scene_type)
memory.add("stage1", "result", d1)
graph, minor_sidecar = stage2_object_graph(image_path, d1)
memory.add("stage2", "result", {"graph": graph, "minor": minor_sidecar})
layout_code = stage3_major_layout_feedback(
image_path=image_path,
scene_description=d1,
scene_graph=graph,
max_iter=config.max_iter,
target_score=config.target,
)
memory.add("stage3", "result", {"code": layout_code})
layout_code = stage4_append_wall_and_visible_minors(layout_code, graph, minor_sidecar)
memory.add("stage4", "result", {"code": layout_code})
descriptions = stage5_describe_objects(image_path, layout_code, memory)
memory.add("stage5_describe", "result", descriptions)
geometry_code, geometry_dict = stage6_replace_proxy_with_parts(layout_code, descriptions)
memory.add("stage6_geometry", "result", {"code": geometry_code, "geometry_dict": geometry_dict})
small_code = stage7_place_surface_small_objects(geometry_code, geometry_dict, minor_sidecar)
if config.detail_small_objects:
small_desc = stage8_describe_small_objects(image_path, small_code, memory)
small_code = stage9_generate_small_object_geometry(small_code, small_desc)
material_code = stage10_assign_pbr_materials(small_code, descriptions, geometry_dict)
texture_code = stage11_inject_real_textures(material_code, image_path, config.stage11_texture_model)
final_code = stage12_setup_lighting_and_render(texture_code, image_path)
return posthoc_correct(final_code)def stage3_major_layout_feedback(image_path, scene_description, scene_graph, max_iter=5, target_score=0.85):
code = generate_initial_blender_layout(image_path, scene_description, scene_graph)
for t in range(1, max_iter + 1):
render_path = render_topdown_with_blender(code, name=f"layout_iter_{t}.png")
critique = vlm_critique_layout(
reference_image=image_path,
rendered_image=render_path,
graph=scene_graph,
checks=["object_coverage", "overlap", "room_boundary", "spatial_relation", "rotation"],
)
if critique.score >= target_score:
break
safe_actions = sanitize_actions(critique.actions, scene_description, scene_graph)
code = revise_blender_code(code, safe_actions)
code = validate_and_patch_python_blender_code(code)
return codedef stage6_replace_proxy_with_parts(layout_code, object_descriptions):
placed = parse_create_box_calls(layout_code)
geometry_dict = {}
for obj in placed:
desc = object_descriptions[obj.name]
parts = vlm_predict_parts(
category=obj.category,
pose=obj.pose,
size=obj.size,
description=desc,
output_schema=["primitive", "semantic_part", "local_size", "offset", "rotation"],
)
parts = clamp_parts_to_proxy(parts, proxy_size=obj.size)
geometry_dict[obj.name] = parts
return rewrite_proxy_constructors(layout_code, geometry_dict), geometry_dictdef stage10_to_12_appearance_and_render(code, geometry_dict, object_descriptions, image_path, config):
material_specs = vlm_assign_part_materials(geometry_dict, object_descriptions)
code = inject_pbr_material_functions(code, material_specs)
texture_manifest = generate_texture_maps(
code=code,
image_path=image_path,
texture_model=config.stage11_texture_model,
image_size=config.stage11_texture_image_size,
max_wall_arts=config.stage11_texture_max_wall_arts,
)
code = rewrite_material_nodes_with_images(code, texture_manifest)
lighting = vlm_analyze_lighting(image_path, code)
code = inject_lighting_and_cycles_settings(code, lighting)
return fix_missing_materials_invalid_paths_camera_and_collisions(code)3.8 Code-to-paper mapping
Code reference:
main@ffd266c6(2026-05-22) — pseudocode and mapping based on this commit
| Paper Concept | Source File | Key Class/Function |
|---|---|---|
| CLI / full 12-stage orchestration | run_pipeline.py | PipelineConfig, UnifiedPipeline, run_full_pipeline, main |
| Cross-stage memory | agent_utils/memory.py | MemoryEntry, Memory.add, Memory.get_latest, Memory.get_context_for_stage, MemoryAwareAgent |
| Scene type routing before Stage 1 | agent_utils/scene_classifier.py | classify_scene, read_scene_type, is_lab |
| Stage 1 spatial semantic analysis | agent_utils/stage1/run_stage1.py | Stage1Runner |
| Stage 2 object-centric scene graph | agent_utils/stage2/run_stage2.py | _build_node_skeleton, _derive_wall_edges, _derive_corner_edges, _merge_skeleton_with_llm, Stage2Runner |
| Stage 3 layout code and visual feedback | agent_utils/stage3/run_stage3.py, agent_utils/stage3/pipeline.py, agent_utils/stage3_rotation.py | Stage3Runner, Stage3Pipeline, Stage3RotationRunner |
| Blender primitive layout harness | IncrementalLayoutEngine.py | create_box, create_cylinder, IncrementalLayoutEngine.add_furniture, find_valid_position |
| Stage 4 wall objects / selected minors | agent_utils/stage4/run_stage4.py | Stage4Runner |
| Stage 5 object description | agent_utils/stage5_describe.py | StageDescribeRunner |
| Stage 6 major-object geometry | agent_utils/stage6_geometry.py | StageGeometryRunner |
| Stage 7–9 small-object extension | agent_utils/stage7_small_objects.py, agent_utils/stage8_small_describe.py, agent_utils/stage9_small_geometry.py | StageSmallObjectsRunner, StageSmallDescribeRunner, StageSmallGeometryRunner |
| Stage 10 material assignment | agent_utils/stage10_material.py | StageMaterialRunner |
| Stage 11 texture generation / injection | agent_utils/stage11_texture.py | StageTextureRunner, texture manifest / material-node rewrite helpers |
| Stage 12 lighting and render settings | agent_utils/stage12_render.py | StageRenderRunner, _analyze_lighting, _inject_lighting_function, _save_results |
| Validation and extraction helpers | agent_utils/validators.py, agent_utils/stage3/core.py | validate_stage1_schema, validate_stage2_object_centric_schema, validate_stage3_code, extract_python_from_response |
| Reproducible run config example | example/pipeline_config.example.json | max_iter=5, target=0.85, start=1, end=12, detail_small_objects=false |
4. Experimental Setup (实验设置)
4.1 Benchmark and data scale
论文构建了一个专门用于 code-based 3D room synthesis 的 benchmark,而不是使用已有室内场景数据集。测试集包含 41 scenes,覆盖不同 room types、scene complexities 和 image styles。普通 residential spaces 包括 bedrooms、kitchens、living rooms,并按 spatial scale 和 object density 分为 Simple、Middle、Hard;此外还包含 laboratories、barber shops、cafes 等 specialized scenes,用于测试模型在非标准家居环境下的泛化。
输入图像类型包括 photorealistic photos、synthetic renderings 和 abstract line drawings。由于这些多源输入没有统一 ground truth,作者采用 human-in-the-loop annotation:先用 Gemini 3.1 在 agent workflow 中生成 coarse labels,再由人工 annotators 通过 reverse code refinement tool 修正,保证视觉编辑和底层 scene code 同步。
4.2 Compared models and baselines
评估分两组。第一组是不同 VLM backbone 在 CaR harness 下的 benchmark:Gemini-3 Flash、Gemini-3.1 Pro、GPT-5.5。第二组是 direct generation / agent baseline:Gemini3.1-Pro single-pass、GPT-5.5 single-pass 和 VIGA。论文说明 Qwen-3.6 与 Claude Opus-4.6 在 preliminary runs 中常常不可用,因此没有纳入主 benchmark。
4.3 Metrics
评估指标分为四类:
- Visual Understanding:Object Recall 衡量 code 是否恢复 annotated objects;Functional Accuracy 衡量 major functional regions 是否重建正确。
- Spatial Reasoning:Self Overlap 越低越好;Layout IoU 衡量布局区域对齐;Spatial Relation Consistency、Rotation Accuracy、Support Accuracy 分别检查关系、朝向和支撑关系。
- Code Generation:Agent Completion 衡量完整 multi-stage pipeline 是否完成;Execution Rate 衡量最终 Blender code 是否可运行。
- Scene Quality:Image Similarity、Scene Usability、Aesthetic Quality 是 VLM-based score;human evaluation 另由 20 experts 对 similarity、usability、lighting alignment 和 acceptability 打分。Acceptability 表示生成场景能否只需少量人工修正就可使用。
4.4 Running / inference config from released code
论文没有报告训练过程、GPU 数量、learning rate 或 batch size;Code-as-Room 主要是 inference-time agentic harness,依赖 VLM/API、Blender 渲染和代码修复。released code 的可复现配置来自 example/pipeline_config.example.json,不是 base default:start=1、end=12、max_iter=5、target=0.85、默认 backbone gemini-3.1-pro-preview-thinking、Stage 11 texture model gemini-3-pro-image-preview、stage11_texture_image_size="1K"、stage11_texture_parallel=8、stage11_texture_max_wall_arts=20、Blender executable path /Applications/Blender.app/Contents/MacOS/Blender、parallel=16、geometry_max_attempts=3、geometry_retry_delay=2.0、material_batch_size=6、material_parallel=4、material_max_attempts=3、detail_small_objects=false。
这说明论文的“training config”栏在本任务中应理解为运行/推理配置:没有 model training,主要超参数是 feedback iteration、score threshold、stage range、并行度、texture generation 设置和 Blender renderer path。
5. Experimental Results (实验结果)
5.1 Main benchmark numbers
Table 1 的核心结论是:直接 single-pass 生成在空间一致性和执行成功率上不稳定,而 CaR harness 可以显著提升不同 VLM backbone 的 object recall、layout IoU、agent completion、execution rate 和 scene quality。
Visual Understanding
| Method | Obj. Recall ↑ | Func. Acc. ↑ |
|---|---|---|
| Gemini3.1-Pro / Single-pass | 17.8% | 15.3% |
| GPT-5.5 / Single-pass | 42.2% | 71.7% |
| Gemini3-Flash w/ CaR | 58.9% | 88.42% |
| Gemini3.1-Pro w/ CaR | 55.5% | 84.3% |
| GPT-5.5 w/ CaR | 67.5% | 72.54% |
Spatial Reasoning
| Method | Self Overlap ↓ | Layout IoU ↑ | Spatial Relation ↑ | Rotation Acc. ↑ | Support Acc. ↑ |
|---|---|---|---|---|---|
| Gemini3.1-Pro / Single-pass | 8.4% | 16.8% | 54.7% | 78.0% | 41.7% |
| GPT-5.5 / Single-pass | 14.5% | 46.2% | 50.8% | 65.3% | 52.6% |
| Gemini3-Flash w/ CaR | 2.57% | 72.0% | 76.9% | 93.5% | 93.5% |
| Gemini3.1-Pro w/ CaR | 3.3% | 73.2% | 79.8% | 93.6% | 94.0% |
| GPT-5.5 w/ CaR | 10.5% | 66.7% | 71.4% | 92.2% | 80.1% |
Code Generation and Scene Quality
| Method | Agent Completion ↑ | Exec. Rate ↑ | Image Similarity ↑ | Scene Usability ↑ | Aesthetic Quality ↑ |
|---|---|---|---|---|---|
| Gemini3.1-Pro / Single-pass | — | 57.8% | 2.49 | 3.24 | 2.51 |
| GPT-5.5 / Single-pass | — | 42.2% | 5.8 | 5.42 | 7.24 |
| Gemini3-Flash w/ CaR | 100% | 100% | 8.32 | 6.07 | 7.17 |
| Gemini3.1-Pro w/ CaR | 100% | 95.5% | 8.08 | 7.05 | 8.20 |
| GPT-5.5 w/ CaR | 71.1% | 73.3% | 7.28 | 6.00 | 7.52 |
Figure 3 解读:这张 qualitative comparison 对应 Table 1。直接 VLM 生成常出现房间结构不完整、物体位置漂移、功能区缺失等问题;CaR 版本能更稳定地保留 top-down input 中的空间比例和家具安排。它直观说明 Table 1 中 Layout IoU、Spatial Relation、Execution Rate 的提升不是孤立指标,而是来自分阶段 layout scaffold 和 feedback loop。
Figure 4 解读:这张图展示了不同 VLM backbone 接入 CaR 后的代表性结果。Gemini-based variants 更容易恢复 shelves、cabinets、decorations、tabletop objects 等局部结构;GPT-5.5 更能保留 coarse layouts,但小细节会简化。论文因此强调,最终质量既依赖 base VLM 能力,也依赖 agentic workflow 如何组织视觉理解、空间推理和代码生成。
Figure 5 解读:Figure 5 进一步放大局部区域,展示细节层面的差异。CaR 的优势不只是“房间大致像”,还包括小型装饰、柜体层级、桌面/墙面物件和局部功能区域的恢复。这支持作者在 Method 中把 object profiling、small-object handling、part-level geometry 和 material stages 单独拆出来的设计。
5.2 Human evaluation
20 位 experts 从 similarity、usability、lighting alignment、acceptability 四个维度评价整体 scene quality。CaR variants 在 similarity / usability / acceptability 上明显优于 direct generation 和 VIGA。
| Method | Sim. ↑ | Use. ↑ | Light ↑ | Accept. ↑ |
|---|---|---|---|---|
| Gemini3.1-Pro / Single-pass | 2.0 | 0.0 | 4.0 | 1.0 |
| GPT-5.5 / Single-pass | 7.0 | 6.0 | 6.5 | 5.0 |
| VIGA | 5.5 | 4.5 | 8.0 | 4.0 |
| CaR w/ GPT-5.5 | 7.5 | 7.0 | 8.0 | 6.5 |
| CaR w/ Gemini3-Flash | 8.5 | 8.0 | 8.0 | 7.5 |
| CaR w/ Gemini3.1-Pro | 9.0 | 8.0 | 8.0 | 7.5 |
Figure 6 解读:这张图直接对比 CaR with Gemini3.1-Pro 和 VIGA。VIGA 更容易生成 template-like scenes,细节缺失、物体位置和局部关系不准确;CaR 保留了 room proportions、furniture arrangements 和 local semantics。它解释了为什么 VIGA 的 Light score 可以达到 8.0,但 Sim. / Use. / Accept. 仍低于 CaR:视觉光照不等于空间布局可用。
5.3 Re-rendering as visual enhancement
作者还用 GPT-5.5 做 image-level re-rendering,以展示 generated Blender scenes 作为 3D structural priors 的潜力。基础 Blender scenes 可编辑且几何一致,但许多对象仍由 primitive shapes 构成,视觉真实感有限;re-rendering 可以在保持 room structure、object layout、spatial relations 和 camera-consistent geometry 的基础上改善材质、光照和对象细节。
Figure 7 解读:左侧是基础 3D scene / rendering,右侧是 GPT-5.5 re-rendering 后的视觉增强结果。关键点是 re-rendering 没有取代 Code-as-Room 的 3D code representation;它依赖 CaR 先提供稳定的几何和语义结构,再把视觉质感提升到更真实的水平。
5.4 Ablation: memory and visual feedback matter
Table 3 分析 cross-stage memory 和 visual feedback iterations。去掉 memory 会让 Object Recall 从 55.5% 降到 48.2%,Layout IoU 从 73.2% 降到 58.0%,Rotation Acc. 从 93.6% 降到 88.4%。这说明后续 stages 如果不能可靠复用早期视觉信息,就会漏物体、弱化空间一致性。
| Configuration | Obj. Recall ↑ | Layout IoU ↑ | Rotation Acc. ↑ |
|---|---|---|---|
| w/o Memory | 48.2% | 58.0% | 88.4% |
| Full Model (Ours) | 55.5% | 73.2% | 93.6% |
| w/o Visual Feedback (0 iter.) | 33.8% | 64.0% | 71.9% |
| Feedback ×3 | 35.6% | 65.7% | 73.2% |
| Feedback ×5 (Ours) | 38.4% | 66.2% | 75.4% |
| Feedback ×10 | 39.1% | 64.2% | 72.6% |
Figure 8 解读:上半部分展示 memory system 的影响:有 memory 时,后续 stages 能继承前面解析出的对象和空间关系;无 memory 时,迭代过程中更容易丢失对象或改变布局。下半部分展示 visual feedback iterations:0 到 5 轮通常能逐步修正缺失物体、位置和朝向;但 10 轮反而可能引入 layout drift 或 over-correction,这与 Table 3 中 Feedback ×10 的 Layout IoU 和 Rotation Acc. 下降一致。
5.5 Limitations and conclusions
作者承认的限制包括:第一,当前方法主要针对从 top-down view image 进行 global 3D scene synthesis,尚未优化 arbitrary-view inputs。第二,很多真实对象很难仅靠 procedural code 精确生成,因为 code-generation models 与 3D asset 的对齐能力有限;更高几何保真度可能仍需要 retrieval-based asset insertion。第三,image re-rendering 可以提升视觉真实感,但当前 video models 对超过五秒轨迹的高质量、时间一致 re-rendering 仍不稳定。
总体结论是:Code-as-Room 的贡献不只是“让 VLM 写 Blender code”,而是提出了一个适配 top-down room image 的 structured execution harness。通过 scene graph skeleton、layout proxy、render-and-compare feedback、typed memory、object-level geometry、material/texture/render stages,系统把一个容易失控的 holistic generation 问题拆成可检查、可修复、可执行的 code synthesis 流程。实验上,CaR 让 Gemini3-Flash 达到 100% agent completion 和 100% execution rate,让 Gemini3.1-Pro w/ CaR 达到 73.2% Layout IoU、94.0% Support Acc.、8.20 Aesthetic Quality,并在 human evaluation 中取得最高 Sim. 9.0、Use. 8.0、Accept. 7.5。