YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

SceneSmith 完整技术文档

语言:中文
对应代码:nepfaff/scenesmith
论文:arXiv 2602.09153
本次运行环境:NVIDIA L40S GPU,SLURM 集群


目录

  1. 系统总览
  2. 输入输出格式
  3. 核心流程详解
  4. 代码结构解析
  5. Robot Eval 模块
  6. SceneSmith 能做什么 / 不能做什么
  7. 本次运行结果
  8. Demo采集说明
  9. 常见问题与局限性
  10. 复现指南

1. 系统总览

SceneSmith 是一个全自动、文本驱动的室内场景生成系统,专为机器人仿真设计。

给一段自然语言描述(如"一个有书桌、床和衣柜的卧室"),SceneSmith 会输出一个物理上可用的完整室内场景,包含:

  • 精确的 6D 物体位姿
  • 每个物体的碰撞几何体(SDF 格式)
  • 物理属性(质量、摩擦系数、惯性矩阵)
  • 可以直接导入 Drake / MuJoCo / Isaac Sim 的格式

系统的核心是用多个 LLM Agent 协作代替人工设计:每个 Agent 负责场景生成的一个阶段,用视觉反馈迭代优化,直到满足质量标准。

文字描述
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│                     SceneSmith Pipeline                   │
│                                                           │
│  Floor Plan Agent → Furniture Agent → Wall Agent          │
│        ↓                 ↓               ↓               │
│  生成平面图          摆放大件家具      墙面装饰            │
│                          ↓               ↓               │
│                    Ceiling Agent → Manipuland Agent       │
│                          ↓               ↓               │
│                    天花板灯具         小件可操作物体       │
│                                                           │
│  每个阶段:LLM 规划 → 3D资产生成 → 物理验证 → 视觉评分    │
└─────────────────────────────────────────────────────────┘
    │
    ▼
house.blend (Blender 渲染) + house.dmd.yaml (Drake 仿真) + house_state.json

2. 输入输出格式

输入

输入项 格式 说明
场景描述 自然语言字符串 例:"A cozy bedroom with a queen bed..."
CSV 提示文件(可选) prompts.csv 批量生成多个场景时使用
配置文件 Hydra YAML 控制使用的模型、后端、参数

prompts.csv 格式

scene_index,prompt
0,"A modern kitchen with..."
1,"A cozy living room with..."

关键配置参数

openai:
  model: "gpt-5.2"              # LLM 模型名
experiment:
  num_scenes: 5                 # 生成场景数量
  scene_prompt: "..."           # 单场景描述
furniture_agent:
  asset_manager:
    backend: "hunyuan3d"        # 3D资产生成后端: sam3d | hunyuan3d | hssd

输出

每次运行生成如下目录结构:

outputs/YYYY-MM-DD/HH-MM-SS/
└── scene_000/
    ├── combined_house/
    │   ├── house.blend               ← Blender 完整场景 (~200MB)
    │   ├── house.dmd.yaml            ← Drake Directives(仿真可用)
    │   ├── house_furniture_welded.dmd.yaml  ← 家具焊接版(稳定性更好)
    │   ├── house_state.json          ← 所有物体的位姿+元数据
    │   └── sceneeval_state.json      ← 场景评分数据
    ├── room_bedroom/
    │   ├── generated_assets/         ← 每个物体的 SDF + 纹理
    │   │   ├── desk_0/
    │   │   │   ├── model.sdf
    │   │   │   ├── model.obj
    │   │   │   └── texture.png
    │   │   └── ...
    │   ├── scene_states/             ← 各阶段保存的中间状态
    │   │   ├── scene_after_furniture/scene.blend
    │   │   ├── scene_after_wall_objects/scene.blend
    │   │   ├── scene_after_ceiling_objects/scene.blend
    │   │   └── final_scene/
    │   │       ├── scene.blend
    │   │       └── scene_state.json
    │   └── scene_renders/            ← 各阶段的渲染图像 (PNG)
    └── floor_plans/
        └── final_floor_plan/
            ├── floor_plan.blend
            └── floor_plan.dmd.yaml

house_state.json 结构(关键字段):

{
  "rooms": {
    "bedroom": {
      "objects": {
        "desk_0": {
          "object_type": "furniture",
          "name": "desk",
          "description": "A modern wooden desk",
          "sdf_path": "generated_assets/desk_0/model.sdf",
          "transform": {
            "translation": [0.79, 1.58, 0.0],
            "rotation_wxyz": [1.0, 0.0, 0.0, 0.0]
          },
          "bbox_min": [-0.6, -0.3, 0.0],
          "bbox_max": [0.6, 0.3, 0.75],
          "mass": 15.0,
          "mu_static": 0.6
        }
      }
    }
  }
}

house.dmd.yaml 格式(Drake Directives):

directives:
- add_model:
    name: bedroom_desk_0
    file: package://scene/room_bedroom/generated_assets/desk_0/model.sdf
- add_weld:
    parent: world
    child: bedroom_desk_0::base_link
    X_PC:
      translation: [0.79, 1.58, 0.0]
      rotation: !Rpy { deg: [0, 0, 0] }

3. 核心流程详解

Stage 1:Floor Plan Agent(平面图规划)

输入:场景描述文字
输出:房间尺寸、门窗位置、墙体布局(floor_plan.dmd.yaml

工作方式:

  1. LLM 解析场景描述,确定所需房间类型(卧室、厨房等)
  2. 生成候选平面图(房间长宽、门的位置)
  3. 用 Blender 渲染俯视图,LLM 评分(0-1分)
  4. 迭代优化,选择得分最高的方案

评分标准:空间合理性、比例、门窗位置是否符合常识。


Stage 2:Furniture Agent(家具摆放)

输入:平面图、场景描述
输出:家具的精确 6D 位姿 + 每件家具的 SDF 模型

这是最复杂的阶段,分三个子步骤:

2a. 家具规划

LLM 决定放什么家具、大概的位置,生成一个结构化的家具列表。

2b. 3D 资产生成

对每件家具,走以下路由(Asset Router):

家具描述文字
    │
    ▼
Asset Router (LLM决策)
    ├── "generated" → Hunyuan3D-2 / SAM3D
    │       ├── 生成参考图 (GPT-Image-2)
    │       └── 图片 → 3D mesh (扩散模型)
    │               ↓
    │       纹理烘焙 + SDF生成
    │
    ├── "artvip" → 从ArtVIP库检索关节物体(开门的衣柜等)
    │
    └── "hssd" → 从HSSD数据集检索(更快,质量稳定)

2c. 迭代摆放

  1. 放置家具到初始位置
  2. Drake 物理仿真:检测碰撞、检查是否可站立
  3. Blender 渲染多视角图
  4. LLM 用视觉反馈打分(美观度、布局合理性、可达性)
  5. 如果分数不满足阈值,调整位置重试(最多 N 轮)

Stage 3:Wall Agent(墙面装饰)

输入:已摆好家具的场景
输出:墙面装饰物(画、镜子、时钟、架子等)的位姿

同样走 asset router → 3D 生成 → Drake 验证 → 视觉评分的流程,但专注于墙面的高度、朝向、装饰品间距。


Stage 4:Ceiling Agent(天花板)

输入:已完成墙面的场景
输出:天花板灯具、风扇等物体

主要验证灯具位置是否在房间中央、是否与墙面冲突。


Stage 5:Manipuland Agent(可操作小物件)

输入:已完成天花板的场景、每件家具的支撑面信息
输出:桌面上的书、杯子、水果等小物件

特点:

  • 自动分析每件家具的"支撑面"(桌面、架子面)
  • 在支撑面上随机采样放置位置,Drake 验证不碰撞
  • 可生成组合(stack/pile/filled_container):叠起来的书、装苹果的碗等

Stage 6:物理投影 + 最终导出

所有物体放好后:

  1. Drake 运行物理仿真,让物体自然落下(消除浮空、轻微穿插)
  2. 输出最终 house.dmd.yaml(固定位姿,weld 到 world)
  3. Blender 渲染最终场景,保存 house.blend

4. 代码结构解析

scenesmith/
├── main.py                    ← 入口,Hydra 配置,调度各 Agent
│
├── scenesmith/
│   ├── experiments/
│   │   └── indoor_scene_generation.py  ← 主实验类,串联所有 Agent
│   │
│   ├── floor_plan_agents/
│   │   ├── stateful_floor_plan_agent.py  ← Floor Plan Agent 实现
│   │   └── tools/                        ← 平面图相关工具
│   │
│   ├── furniture_agents/
│   │   ├── stateful_furniture_agent.py   ← Furniture Agent 主类
│   │   └── tools/
│   │       ├── furniture_tools.py        ← 家具放置、物理检查工具
│   │       ├── vision_tools.py           ← Blender 渲染观察工具
│   │       └── scene_tools.py            ← 场景状态查询
│   │
│   ├── wall_agents/           ← Wall Agent(同结构)
│   ├── ceiling_agents/        ← Ceiling Agent(同结构)
│   ├── manipuland_agents/     ← Manipuland Agent(同结构)
│   │
│   ├── agent_utils/
│   │   ├── asset_manager.py       ← 资产获取总入口
│   │   ├── asset_router/          ← LLM决策走哪个资产后端
│   │   ├── geometry_generation_server/  ← 3D生成服务(Hunyuan3D工作进程)
│   │   │   ├── server_manager.py
│   │   │   ├── worker_pool.py     ← GPU工作进程池
│   │   │   └── gpu_worker.py      ← 单个GPU的3D生成进程
│   │   ├── drake_utils.py         ← Drake 仿真工具
│   │   ├── rendering.py           ← 场景渲染工具
│   │   ├── physics_validation.py  ← 物理碰撞检测
│   │   ├── reachability.py        ← 机器人可达性分析
│   │   ├── image_generation.py    ← 参考图生成(GPT-Image-2)
│   │   ├── vlm_service.py         ← VLM评分服务
│   │   └── blender/               ← Blender 进程通信
│   │       ├── server_manager.py  ← Blender 服务器管理
│   │       └── renderer.py        ← 渲染接口
│   │
│   └── robot_eval/
│       ├── dmd_scene.py              ← Drake 场景加载
│       ├── policy_interface/
│       │   ├── policy_agent.py       ← 任务 → 物体绑定 Agent
│       │   └── predicate_resolver.py ← 绑定 → 精确位姿
│       ├── success_validation/
│       │   └── validator_agent.py    ← 任务成功验证 Agent
│       └── task_generation/
│           └── scene_prompt_generator.py ← 任务 → 场景描述
│
└── scripts/
    ├── robot_eval/
    │   ├── generate_prompts.py   ← Stage 1: task → prompts
    │   ├── policy_interface.py   ← Stage 3: scene + task → robot poses
    │   └── validate.py           ← Stage 4: 验证任务完成
    ├── collect_demo.py           ← Demo采集与可视化(本次添加)
    ├── render_flythrough.py      ← 生成场景飞行视频
    └── export_scene_to_mujoco.py ← 导出到 MuJoCo

关键类说明

StatefulFurnitureAgent

继承自 BaseStatefulAgent,用 openai-agents SDK 运行 LLM agent loop。

Agent 的 tools 包括:

  • place_furniture(obj_id, x, y, yaw) — 放置家具
  • observe_scene() — 渲染当前场景,返回多视角图给 LLM 看
  • get_physics_check() — 运行 Drake 碰撞检测
  • generate_furniture_assets(descriptions) — 批量生成 3D 资产
  • score_scene() — VLM 打分

每轮 LLM 调用 tools → 观察反馈 → 调整 → 直到评分达标或超过最大轮数。

AssetManager

统一的资产获取接口,内部调用 AssetRouter 决策:

asset = await asset_manager.get_asset(
    description="A wooden desk with drawers",
    object_type="furniture",
    strategy="generated"  # or "hssd", "artvip"
)
# 返回 Asset(sdf_path, obj_path, texture_path, dimensions, ...)

DMDScene + PredicateResolver

用于 robot eval:

scene = load_scene_for_validation(
    scene_state_path=Path("house_state.json"),
    dmd_path=Path("house.dmd.yaml"),
)
scene.finalize()  # 建立 Drake plant,同步位姿

resolver = PredicateResolver(scene=scene, cfg=cfg)
result = resolver.resolve("Pick the apple and place it on the plate")
# result.poses[0].target_position → [x, y, z] 目标位姿
# result.poses[0].placement_bounds_min/max → 有效放置区域 AABB

5. Robot Eval 模块

这是 SceneSmith 的机器人评测框架,共 4 个阶段:

阶段 1:生成场景提示词

python scripts/robot_eval/generate_prompts.py \
    --task "Pick a fruit from the bowl and place it on the plate" \
    --output-dir outputs/eval_run \
    --num-prompts 5

LLM 分析 task,提取:

  • 必须存在的物体(水果、碗、盘子)
  • 初始状态约束(水果不能已经在盘子上)
  • 可变的风格维度(厨房风格、其他装饰物)

输出 prompts.csvmain.py 生成多个不同风格的场景。

阶段 2:生成场景

python main.py +name=eval experiment.csv_path=outputs/eval_run/prompts.csv

阶段 3:Policy Interface(任务 → 机器人位姿)

python scripts/robot_eval/policy_interface.py \
    --scene-state outputs/.../house_state.json \
    --dmd outputs/.../house.dmd.yaml \
    --task "Pick a fruit from the bowl and place it on the plate" \
    --output-json robot_commands.json

输出格式:

{
  "task": "Pick a fruit...",
  "robot_start_xy": [1.2, -0.5],
  "world_bounds": {"min": [-3, -3, 0], "max": [3, 3, 2.7]},
  "commands": [{
    "action": "pick_and_place",
    "rank": 1,
    "confidence": 0.92,
    "drake_model_name": "bedroom_apple_0",
    "target_position": [0.5, 0.3, 0.85],
    "placement_bounds_min": [0.2, 0.1, 0.85],
    "placement_bounds_max": [0.8, 0.5, 1.0],
    "reasoning": "Apple found on nightstand (precondition met), plate on desk is valid goal"
  }]
}

注意:SceneSmith 不包含 robot URDF 和 policy。placement_bounds_min/max 是给你的 policy 用的采样区域。

阶段 4:验证

Robot 执行完任务后,将修改过的 house.dmd.yaml(更新了物体位姿)传入验证器:

python scripts/robot_eval/validate.py \
    --scene-state outputs/.../house_state.json \
    --dmd outputs/.../modified_house.dmd.yaml \
    --task "Pick a fruit from the bowl and place it on the plate"

验证器用 Drake 物理查询(签名距离、接触检测)+ VLM 视觉判断,输出每个子要求的得分。


6. SceneSmith 能做什么 / 不能做什么

✅ 能做的

场景类型 说明
卧室 床、衣柜、书桌、台灯、挂画、小件(书、闹钟等)
厨房 橱柜、餐桌、厨具、水果、杯子等
办公室 桌子、椅子、电脑、文具等
客厅 沙发、茶几、书架、摆件等
关节物体 可开关的柜子、抽屉(来自 ArtVIP 数据集)
桌面操作场景 通过 manipuland agent 生成多个小物件,支持 pick-and-place
组合物体 叠起来的书(stack)、装了东西的碗(filled_container)、散乱的一堆(pile)

❌ 不能做的

类别 原因
柔性物体(布料、毛绒玩具) SceneSmith 只生成刚体 SDF。柔性物体需要 FEM/粒子仿真,Drake 支持有限,SceneSmith 不建模
流体(倒水、液体) 同上,流体需要 SPH/粒子系统,不在 SceneSmith 范围内。house.dmd.yaml 是刚体 Directives
人体/角色动画 无 URDF/骨骼,无动画系统
室外场景 专为室内设计,无地形、植被等
Robot URDF SceneSmith 只生成环境,不包含机器人本体
Policy / Controller 不包含任何 policy,只提供场景 + eval harness

关于柔性物体和流体的正确路径

如果需要:

  • 布料:用 MuJoCo 的 composite 元素或 Isaac Sim 的 FEM,把 SceneSmith 生成的刚体场景作为背景
  • 流体:FluidLab、Taichi,SceneSmith 生成杯子/瓶子的 SDF 作为容器几何体
  • 可以用 scripts/export_scene_to_mujoco.py 先把 SceneSmith 场景转成 MuJoCo XML,再在 MuJoCo 里加入柔性/流体模拟

7. 本次运行结果

场景 1:卧室(Bedroom)

提示词

A cozy bedroom with a queen bed against the wall, two nightstands with lamps, a wardrobe in the corner, and a small desk with a chair near the window.

运行时间:约 1 小时 57 分钟(L40S GPU)

生成物体

物体 类型 位置 (x, y, z)
desk_0 furniture (0.79, 1.58, 0.0)
nightstand_0 furniture (-0.55, -1.73, 0.0)
nightstand_1 furniture (0.62, -1.73, 0.0)
rug_0 furniture (-0.01, -0.39, 0.0)
wardrobe_0 furniture (2.06, -1.53, 0.0)

注意:本次运行中 Hunyuan3D worker 因 CUDA fork 问题未能生成 manipuland(小件物体),house_state.json 只有家具级别的物体。

输出文件

  • combined_house/house.blend — 201MB Blender 场景
  • combined_house/flythrough.mp4 — 120帧 1280×720 飞行视频
  • combined_house/house.dmd.yaml — Drake 仿真文件

8. Demo采集说明

什么是 Demo

在这里,"demo" 是指一个 pick-and-place 任务的完整轨迹,包含:

  • 初始场景状态(物体位姿)
  • 末端执行器的完整轨迹(6D位姿序列)
  • 夹爪宽度序列
  • 任务成功与否

本次 Demo 类型

由于 SceneSmith 不含真实 robot,我们采用 scripted demo(脚本化轨迹),按照标准 pick-and-place 轨迹规划:

Home → Approach(接近物体上方)→ Pre-grasp(下降)→ Grasp(夹爪闭合)
→ Lift(提升)→ Transport(平移)→ Place(放下)→ Release(张开夹爪)

与真实采集的区别

项目 本次(脚本化) 真实采集
轨迹来源 几何规划 robot controller / teleop
物理真实性 运动学插值 力矩控制
碰撞避免 简单直线轨迹 运动规划(RRT等)
接触建模 Drake/MuJoCo 物理仿真
用途 演示、可视化 训练 policy

Demo JSON 格式

{
  "task": "Pick an object from the nightstand and place it on the desk",
  "scene_id": "bedroom_nightstand_to_desk",
  "target_object": "bedroom_nightstand_0",
  "initial_pos": [-0.55, -1.73, 0.5],
  "goal_pos": [0.79, 1.58, 0.85],
  "goal_reference": "bedroom_desk_0",
  "success": true,
  "total_duration_s": 7.5,
  "num_steps": 150,
  "trajectory": [
    {
      "step_id": 0,
      "phase": "approach",
      "end_effector_pos": [0.0, 0.0, 0.8],
      "end_effector_quat_wxyz": [1, 0, 0, 0],
      "gripper_width": 1.0,
      "target_object_pos": [-0.55, -1.73, 0.5],
      "timestamp": 0.0
    },
    ...
  ]
}

可视化说明

demo_*_trajectory.png 包含 4 个子图:

  1. 3D 轨迹图:不同颜色表示不同阶段(接近/抓取/搬运/放置)
  2. 俯视图(XY平面):路径规划可视化
  3. 高度-时间曲线:末端执行器与物体的 Z 轴变化
  4. 夹爪宽度-时间曲线:抓取动作可视化

9. 常见问题与局限性

Q: Hunyuan3D-2 生成质量很差怎么办?

A: 换 SAM3D 后端(需要 A100/H100,无 gated 访问限制)。Hunyuan3D 官方说明仅作 proof-of-concept,质量明显劣于 SAM3D。

Q: manipuland 物体没有生成?

A: Hunyuan3D worker 在 fork 后 CUDA 重初始化失败。症状:Worker shutting down. Stats: 279 total, 0 completed, 279 failed。解决:换用 strategy: "hssd" 检索模式,不依赖 CUDA generation。

Q: LLM 返回 rs_* 错误?

A: LiteLLM 代理是无状态的,不支持 server-side reasoning 续接。需要设置 reasoning_effort: none 并使用自定义 NvidiaInferenceProvider(已在本次配置中修复)。

Q: 一次运行需要多久?

A: 单房间约 1-2 小时(L40S, Hunyuan3D)。SAM3D 质量更好但更慢。多 GPU 可以并行生成多个房间。

Q: 能生成多房间场景吗?

A: 可以,在 scene_prompt 中描述多个房间,experiment.num_scenes 控制变体数量。

Q: 如何接入自己的 robot?

A:

  1. 加载 house.dmd.yaml 到 Drake/MuJoCo
  2. policy_interface.py 获取 task 的目标位姿
  3. 用你自己的 robot controller 执行
  4. 将结果写回修改后的 .dmd.yaml
  5. validate.py 验证成功率

10. 复现指南

环境要求

  • Python 3.11
  • CUDA 12.4(编译 custom_rasterizer)
  • Blender 5.1(headless,EEVEE 渲染)
  • SLURM 集群,L40S GPU(48GB)

安装步骤

# 1. 克隆仓库
git clone https://github.com/nepfaff/scenesmith.git
cd scenesmith
git submodule update --init --recursive

# 2. 创建虚拟环境
uv sync --no-dev

# 3. 安装 Hunyuan3D-2
bash scripts/install_hunyuan3d.sh

# 4. 下载 ArtVIP 数据
huggingface-cli download nepfaff/scenesmith-preprocessed-data \
    artvip/artvip_vhacd.tar.gz --repo-type dataset --local-dir .
mkdir -p data/artvip_sdf
tar xzf artvip/artvip_vhacd.tar.gz -C data/artvip_sdf

# 5. 下载材质
python scripts/download_ambientcg.py --output data/materials
# 下载材质嵌入(从 HF)

# 6. 编译 CUDA 扩展(需要 CUDA toolkit)
# 见 cuda_home/ 目录的说明

运行

# 设置环境变量
export OPENAI_API_KEY=<your_key>
export OPENAI_BASE_URL=https://inference-api.nvidia.com/v1
export HF_TOKEN=<your_hf_token>

# 生成场景
python main.py \
    "+name=my_scene" \
    "experiment.scene_prompt=A cozy bedroom with a bed and desk" \
    "openai.model=azure/openai/gpt-5.2" \
    "furniture_agent.asset_manager.backend=hunyuan3d" \
    "furniture_agent.reasoning_effort.generation=none"

# 渲染视频
python scripts/render_flythrough.py \
    --blend outputs/.../combined_house/house.blend \
    --output flythrough.mp4 \
    --blender /path/to/blender

# 采集 Demo
python scripts/collect_demo.py \
    --scene-state outputs/.../house_state.json \
    --dmd outputs/.../house.dmd.yaml \
    --task "Pick the book and place it on the desk" \
    --output-dir demos/

本次运行的关键 Patch

本次在 NVIDIA 内部集群运行时,在原始代码基础上做了以下修改:

  1. **nvidia_inference_provider.py**(新增):绕过 openai-agents SDK 对 azure/openai/gpt-5.2 的前缀解析,直接路由到 inference-api.nvidia.com
  2. **base_stateful_agent.py**:注入自定义 Provider
  3. 所有 YAML 配置reasoning_effort: none,防止 stateful reasoning items
  4. **worker_pool.py**:限制 CUDA re-init 重试次数(max 3次)
  5. **render_flythrough.py**(新增):适配 Blender 5.1 新 API(action.layers[].strips[].channelbags[].fcurves
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Paper for yqi19/scenesmith