|
16 | 16 |
|
17 | 17 | import json |
18 | 18 | import os |
19 | | -from copy import deepcopy |
20 | 19 |
|
21 | 20 | import numpy as np |
22 | 21 | import sapien |
|
26 | 25 | from mani_skill.sensors.camera import CameraConfig |
27 | 26 | from mani_skill.utils import sapien_utils |
28 | 27 | from mani_skill.utils.building import actors |
| 28 | +from mani_skill.utils.building.ground import build_ground |
29 | 29 | from mani_skill.utils.registration import register_env |
30 | 30 | from mani_skill.utils.structs.actor import Actor |
31 | 31 | from mani_skill.utils.structs.pose import Pose |
@@ -78,6 +78,14 @@ def __init__( |
78 | 78 | # Add small offset in z-axis to avoid collision. |
79 | 79 | self.objs_z_offset = kwargs.pop("objs_z_offset", 0.002) |
80 | 80 | self.robot_z_offset = kwargs.pop("robot_z_offset", 0.002) |
| 81 | + self.camera_cfg = kwargs.pop("camera_cfg", None) |
| 82 | + if self.camera_cfg is None: |
| 83 | + self.camera_cfg = dict( |
| 84 | + camera_eye=[0.9, 0.0, 1.1], |
| 85 | + camera_target_pt=[0.0, 0.0, 0.9], |
| 86 | + image_hw=[256, 256], |
| 87 | + fovy_deg=75, |
| 88 | + ) |
81 | 89 |
|
82 | 90 | self.layouts = self.init_env_layouts( |
83 | 91 | layout_file, num_envs, replace_objs |
@@ -106,22 +114,30 @@ def __init__( |
106 | 114 | def init_env_layouts( |
107 | 115 | layout_file: str, num_envs: int, replace_objs: bool |
108 | 116 | ) -> list[LayoutInfo]: |
109 | | - layout = LayoutInfo.from_dict(json.load(open(layout_file, "r"))) |
110 | 117 | layouts = [] |
111 | 118 | for env_idx in range(num_envs): |
112 | 119 | if replace_objs and env_idx > 0: |
113 | | - layout = bfs_placement(deepcopy(layout)) |
114 | | - layouts.append(layout) |
| 120 | + layout_info = bfs_placement(layout_file) |
| 121 | + else: |
| 122 | + layout_info = json.load(open(layout_file, "r")) |
| 123 | + layout_info = LayoutInfo.from_dict(layout_info) |
| 124 | + |
| 125 | + layout_path = layout_file.replace(".json", f"_env{env_idx}.json") |
| 126 | + with open(layout_path, "w") as f: |
| 127 | + json.dump(layout_info.to_dict(), f, indent=4) |
| 128 | + |
| 129 | + layouts.append(layout_path) |
115 | 130 |
|
116 | 131 | return layouts |
117 | 132 |
|
118 | 133 | @staticmethod |
119 | 134 | def compute_robot_init_pose( |
120 | | - layouts: list[LayoutInfo], num_envs: int, z_offset: float = 0.0 |
| 135 | + layouts: list[str], num_envs: int, z_offset: float = 0.0 |
121 | 136 | ) -> list[list[float]]: |
122 | 137 | robot_pose = [] |
123 | 138 | for env_idx in range(num_envs): |
124 | | - layout = layouts[env_idx] |
| 139 | + layout = json.load(open(layouts[env_idx], "r")) |
| 140 | + layout = LayoutInfo.from_dict(layout) |
125 | 141 | robot_node = layout.relation[Scene3DItemEnum.ROBOT.value] |
126 | 142 | x, y, z, qx, qy, qz, qw = layout.position[robot_node] |
127 | 143 | robot_pose.append([x, y, z + z_offset, qw, qx, qy, qz]) |
@@ -154,19 +170,27 @@ def _default_sensor_configs(self): |
154 | 170 | @property |
155 | 171 | def _default_human_render_camera_configs(self): |
156 | 172 | pose = sapien_utils.look_at( |
157 | | - eye=[0.9, 0.0, 1.1], target=[0.0, 0.0, 0.9] |
| 173 | + eye=self.camera_cfg["camera_eye"], |
| 174 | + target=self.camera_cfg["camera_target_pt"], |
158 | 175 | ) |
159 | 176 |
|
160 | 177 | return CameraConfig( |
161 | | - "render_camera", pose, 256, 256, np.deg2rad(75), 0.01, 100 |
| 178 | + "render_camera", |
| 179 | + pose, |
| 180 | + self.camera_cfg["image_hw"][1], |
| 181 | + self.camera_cfg["image_hw"][0], |
| 182 | + np.deg2rad(self.camera_cfg["fovy_deg"]), |
| 183 | + 0.01, |
| 184 | + 100, |
162 | 185 | ) |
163 | 186 |
|
164 | 187 | def _load_agent(self, options: dict): |
| 188 | + self.ground = build_ground(self.scene) |
165 | 189 | super()._load_agent(options, sapien.Pose(p=[-10, 0, 10])) |
166 | 190 |
|
167 | 191 | def _load_scene(self, options: dict): |
168 | 192 | all_objects = [] |
169 | | - logger.info(f"Loading assets and decomposition mesh collisions...") |
| 193 | + logger.info(f"Loading EmbodiedGen assets...") |
170 | 194 | for env_idx in range(self.num_envs): |
171 | 195 | env_actors = load_assets_from_layout_file( |
172 | 196 | self.scene, |
@@ -229,20 +253,26 @@ def _initialize_episode(self, env_idx: torch.Tensor, options: dict): |
229 | 253 | self.agent.controller.controllers["gripper"].reset() |
230 | 254 |
|
231 | 255 | def render_gs3d_images( |
232 | | - self, layouts: list[LayoutInfo], num_envs: int, init_quat: list[float] |
| 256 | + self, layouts: list[str], num_envs: int, init_quat: list[float] |
233 | 257 | ) -> dict[str, np.ndarray]: |
234 | 258 | sim_coord_align = ( |
235 | 259 | torch.tensor(SIM_COORD_ALIGN).to(torch.float32).to(self.device) |
236 | 260 | ) |
237 | 261 | cameras = self.scene.sensors.copy() |
238 | 262 | cameras.update(self.scene.human_render_cameras) |
239 | 263 |
|
240 | | - bg_node = layouts[0].relation[Scene3DItemEnum.BACKGROUND.value] |
241 | | - gs_path = os.path.join(layouts[0].assets[bg_node], "gs_model.ply") |
| 264 | + # Preload the background Gaussian Splatting model. |
| 265 | + asset_root = os.path.dirname(layouts[0]) |
| 266 | + layout = LayoutInfo.from_dict(json.load(open(layouts[0], "r"))) |
| 267 | + bg_node = layout.relation[Scene3DItemEnum.BACKGROUND.value] |
| 268 | + gs_path = os.path.join( |
| 269 | + asset_root, layout.assets[bg_node], "gs_model.ply" |
| 270 | + ) |
242 | 271 | raw_gs: GaussianOperator = GaussianOperator.load_from_ply(gs_path) |
243 | 272 | bg_images = dict() |
244 | 273 | for env_idx in tqdm(range(num_envs), desc="Pre-rendering Background"): |
245 | | - layout = layouts[env_idx] |
| 274 | + layout = json.load(open(layouts[env_idx], "r")) |
| 275 | + layout = LayoutInfo.from_dict(layout) |
246 | 276 | x, y, z, qx, qy, qz, qw = layout.position[bg_node] |
247 | 277 | qx, qy, qz, qw = quaternion_multiply([qx, qy, qz, qw], init_quat) |
248 | 278 | init_pose = torch.tensor([x, y, z, qx, qy, qz, qw]) |
|
0 commit comments