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. 系统总览
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)
工作方式:
- LLM 解析场景描述,确定所需房间类型(卧室、厨房等)
- 生成候选平面图(房间长宽、门的位置)
- 用 Blender 渲染俯视图,LLM 评分(0-1分)
- 迭代优化,选择得分最高的方案
评分标准:空间合理性、比例、门窗位置是否符合常识。
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. 迭代摆放
- 放置家具到初始位置
- Drake 物理仿真:检测碰撞、检查是否可站立
- Blender 渲染多视角图
- LLM 用视觉反馈打分(美观度、布局合理性、可达性)
- 如果分数不满足阈值,调整位置重试(最多 N 轮)
Stage 3:Wall Agent(墙面装饰)
输入:已摆好家具的场景
输出:墙面装饰物(画、镜子、时钟、架子等)的位姿
同样走 asset router → 3D 生成 → Drake 验证 → 视觉评分的流程,但专注于墙面的高度、朝向、装饰品间距。
Stage 4:Ceiling Agent(天花板)
输入:已完成墙面的场景
输出:天花板灯具、风扇等物体
主要验证灯具位置是否在房间中央、是否与墙面冲突。
Stage 5:Manipuland Agent(可操作小物件)
输入:已完成天花板的场景、每件家具的支撑面信息
输出:桌面上的书、杯子、水果等小物件
特点:
- 自动分析每件家具的"支撑面"(桌面、架子面)
- 在支撑面上随机采样放置位置,Drake 验证不碰撞
- 可生成组合(stack/pile/filled_container):叠起来的书、装苹果的碗等
Stage 6:物理投影 + 最终导出
所有物体放好后:
- Drake 运行物理仿真,让物体自然落下(消除浮空、轻微穿插)
- 输出最终
house.dmd.yaml(固定位姿,weld 到 world) - 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.csv 供 main.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 个子图:
- 3D 轨迹图:不同颜色表示不同阶段(接近/抓取/搬运/放置)
- 俯视图(XY平面):路径规划可视化
- 高度-时间曲线:末端执行器与物体的 Z 轴变化
- 夹爪宽度-时间曲线:抓取动作可视化
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:
- 加载
house.dmd.yaml到 Drake/MuJoCo - 用
policy_interface.py获取 task 的目标位姿 - 用你自己的 robot controller 执行
- 将结果写回修改后的
.dmd.yaml - 用
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 内部集群运行时,在原始代码基础上做了以下修改:
- **
nvidia_inference_provider.py**(新增):绕过openai-agentsSDK 对azure/openai/gpt-5.2的前缀解析,直接路由到inference-api.nvidia.com - **
base_stateful_agent.py**:注入自定义 Provider - 所有 YAML 配置:
reasoning_effort: none,防止 stateful reasoning items - **
worker_pool.py**:限制 CUDA re-init 重试次数(max 3次) - **
render_flythrough.py**(新增):适配 Blender 5.1 新 API(action.layers[].strips[].channelbags[].fcurves)