# SceneSmith 完整技术文档 > 语言:中文 > 对应代码:[nepfaff/scenesmith](https://github.com/nepfaff/scenesmith) > 论文:[arXiv 2602.09153](https://arxiv.org/abs/2602.09153) > 本次运行环境:NVIDIA L40S GPU,SLURM 集群 --- ## 目录 1. [系统总览](#1-系统总览) 2. [输入输出格式](#2-输入输出格式) 3. [核心流程详解](#3-核心流程详解) 4. [代码结构解析](#4-代码结构解析) 5. [Robot Eval 模块](#5-robot-eval-模块) 6. [SceneSmith 能做什么 / 不能做什么](#6-scenesmith-能做什么--不能做什么) 7. [本次运行结果](#7-本次运行结果) 8. [Demo采集说明](#8-demo采集说明) 9. [常见问题与局限性](#9-常见问题与局限性) 10. [复现指南](#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` 格式**: ```csv scene_index,prompt 0,"A modern kitchen with..." 1,"A cozy living room with..." ``` **关键配置参数**: ```yaml 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` 结构**(关键字段): ```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): ```yaml 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` 决策: ```python 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: ```python 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:生成场景提示词 ```bash 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:生成场景 ```bash python main.py +name=eval experiment.csv_path=outputs/eval_run/prompts.csv ``` ### 阶段 3:Policy Interface(任务 → 机器人位姿) ```bash 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 ``` 输出格式: ```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`(更新了物体位姿)传入验证器: ```bash 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 格式 ```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) ### 安装步骤 ```bash # 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/ 目录的说明 ``` ### 运行 ```bash # 设置环境变量 export OPENAI_API_KEY= export OPENAI_BASE_URL=https://inference-api.nvidia.com/v1 export 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`)