@@ -91,6 +91,7 @@ def __init__(
9191 self ._is_built = False
9292 self ._attached_link = None
9393 self ._attached_offset_T = None
94+ self ._attached_env_idx = None
9495
9596 self ._in_recording = False
9697 self ._recorded_imgs = []
@@ -124,7 +125,7 @@ def _build(self):
124125 self ._is_built = True
125126 self .set_pose (self ._transform , self ._pos , self ._lookat , self ._up )
126127
127- def attach (self , rigid_link , offset_T ):
128+ def attach (self , rigid_link , offset_T , env_idx : int | None = None ):
128129 """
129130 Attach the camera to a rigid link in the scene.
130131
@@ -136,9 +137,25 @@ def attach(self, rigid_link, offset_T):
136137 The rigid link to which the camera should be attached.
137138 offset_T : np.ndarray, shape (4, 4)
138139 The transformation matrix specifying the camera's pose relative to the rigid link.
140+ env_idx : int
141+ The environment index this camera should be tied to. Offsets the `offset_T` accordingly. Must be specified if running parallel environments
142+
143+ Raises
144+ ------
145+ Exception
146+ If running parallel simulations but env_idx is not specified.
147+ Exception
148+ If invalid env_idx is specified (env_idx >= n_envs)
139149 """
140150 self ._attached_link = rigid_link
141151 self ._attached_offset_T = offset_T
152+ if self ._visualizer ._scene .n_envs > 0 and env_idx is None :
153+ gs .raise_exception ("Must specify env_idx when running parallel simulations" )
154+ if env_idx is not None :
155+ n_envs = self ._visualizer ._scene .n_envs
156+ if env_idx >= n_envs :
157+ gs .raise_exception (f"Invalid env_idx { env_idx } for camera, configured for { n_envs } environments" )
158+ self ._attached_env_idx = env_idx
142159
143160 def detach (self ):
144161 """
@@ -148,6 +165,7 @@ def detach(self):
148165 """
149166 self ._attached_link = None
150167 self ._attached_offset_T = None
168+ self ._attached_env_idx = None
151169
152170 @gs .assert_built
153171 def move_to_attach (self ):
@@ -160,16 +178,15 @@ def move_to_attach(self):
160178 ------
161179 Exception
162180 If the camera has not been mounted using `attach()`.
163- Exception
164- If the simulation is running in parallel (`n_envs > 0`), which is currently unsupported for mounted cameras.
165181 """
166182 if self ._attached_link is None :
167183 gs .raise_exception (f"The camera hasn't been mounted!" )
168- if self ._visualizer ._scene .n_envs > 0 :
169- gs .raise_exception (f"Mounted camera not supported in parallel simulation!" )
170184
171- link_pos = self ._attached_link .get_pos ().cpu ().numpy ()
172- link_quat = self ._attached_link .get_quat ().cpu ().numpy ()
185+ link_pos = self ._attached_link .get_pos (envs_idx = self ._attached_env_idx ).cpu ().numpy ()
186+ link_quat = self ._attached_link .get_quat (envs_idx = self ._attached_env_idx ).cpu ().numpy ()
187+ if self ._attached_env_idx is not None :
188+ link_pos = link_pos [0 ] + self ._visualizer ._scene .envs_offset [self ._attached_env_idx ]
189+ link_quat = link_quat [0 ]
173190 link_T = gu .trans_quat_to_T (link_pos , link_quat )
174191 transform = link_T @ self ._attached_offset_T
175192 self .set_pose (transform = transform )
0 commit comments