2424from genesis .options .renderers import BatchRenderer as BatchRendererOptions
2525from genesis .options .vis import VisOptions
2626from genesis .vis .rasterizer_context import RasterizerContext
27- from .base_sensor import Sensor , SharedSensorMetadata , RigidSensorMixin , RigidSensorMetadataMixin
27+ from .base_sensor import (
28+ Sensor ,
29+ SharedSensorMetadata ,
30+ RigidSensorMixin ,
31+ RigidSensorMetadataMixin ,
32+ )
2833from .sensor_manager import register_sensor
2934
3035
@@ -195,7 +200,13 @@ class BaseCameraSensor(RigidSensorMixin, Sensor[SharedSensorMetadata]):
195200 - Shared read() method returning torch tensors
196201 """
197202
198- def __init__ (self , options : "SensorOptions" , idx : int , data_cls : Type [CameraData ], manager : "gs.SensorManager" ):
203+ def __init__ (
204+ self ,
205+ options : "SensorOptions" ,
206+ idx : int ,
207+ data_cls : Type [CameraData ],
208+ manager : "gs.SensorManager" ,
209+ ):
199210 super ().__init__ (options , idx , data_cls , manager )
200211 self ._stale : bool = True
201212
@@ -211,7 +222,9 @@ def _get_cache_dtype(cls) -> torch.dtype:
211222
212223 @classmethod
213224 def _update_shared_ground_truth_cache (
214- cls , shared_metadata : SharedSensorMetadata , shared_ground_truth_cache : torch .Tensor
225+ cls ,
226+ shared_metadata : SharedSensorMetadata ,
227+ shared_ground_truth_cache : torch .Tensor ,
215228 ):
216229 pass
217230
@@ -246,7 +259,10 @@ def move_to_attach(self):
246259 offset_T = torch .tensor (self ._options .offset_T , dtype = gs .tc_float , device = gs .device )
247260 else :
248261 pos = torch .tensor (self ._options .pos , dtype = gs .tc_float , device = gs .device )
249- offset_T = trans_quat_to_T (pos , torch .tensor ([1.0 , 0.0 , 0.0 , 0.0 ], dtype = gs .tc_float , device = gs .device ))
262+ offset_T = trans_quat_to_T (
263+ pos ,
264+ torch .tensor ([1.0 , 0.0 , 0.0 , 0.0 ], dtype = gs .tc_float , device = gs .device ),
265+ )
250266
251267 link_pos = self ._link .get_pos ()
252268 link_quat = self ._link .get_quat ()
@@ -423,11 +439,29 @@ def build(self):
423439
424440 def _create_standalone_context (self , scene ):
425441 """Create a simplified RasterizerContext for camera sensors."""
442+ if not scene .sim ._rigid_only and scene .n_envs > 1 :
443+ gs .raise_exception ("Rasterizer with n_envs > 1, does not work when using non rigid simulation" )
444+ if sys .platform == "darwin" :
445+ if scene .n_envs > 1 :
446+ gs .raise_exception (
447+ "Rasterizer with n_envs > 1, does not work on Metal because it doesn't support OpenGL 4.2"
448+ )
449+ env_separate_rigid = False
450+ else :
451+ if self ._link is not None :
452+ gs .raise_exception ("Rasterizer with n_envs > 1, does not work with attached cameras yet." )
453+
454+ if scene .n_envs > 1 :
455+ gs .logger .warning (
456+ "Rasterizer with n_envs > 1 is slow as it doesn't do batched rendering consider using BatchRenderer instead."
457+ )
458+ env_separate_rigid = True
426459 vis_options = VisOptions (
427460 show_world_frame = False ,
428461 show_link_frame = False ,
429462 show_cameras = False ,
430463 rendered_envs_idx = range (max (self ._manager ._sim ._B , 1 )),
464+ env_separate_rigid = env_separate_rigid ,
431465 )
432466
433467 context = RasterizerContext (vis_options )
@@ -501,22 +535,19 @@ def _render_current_state(self):
501535 self ._shared_metadata .context .update (force_render = True )
502536
503537 rgb_arr , _ , _ , _ = self ._shared_metadata .renderer .render_camera (
504- self ._get_camera_wrapper (), rgb = True , depth = False , segmentation = False , normal = False
538+ self ._get_camera_wrapper (),
539+ rgb = True ,
540+ depth = False ,
541+ segmentation = False ,
542+ normal = False ,
505543 )
506544
507545 rgb_tensor = torch .from_numpy (rgb_arr .copy ()).to (dtype = torch .uint8 , device = gs .device )
508546
509- # Store in cache
510- n_envs = self ._manager ._sim ._B
511- if n_envs <= 1 :
512- # Single environment case - add batch dimension
513- self ._shared_metadata .image_cache [self ._idx ][0 ] = rgb_tensor
514- else :
515- # Multi-environment rendering is not yet supported for Rasterizer cameras
516- gs .raise_exception (
517- f"Rasterizer camera sensors do not support multi-environment rendering (n_envs={ n_envs } ). "
518- "Use BatchRenderer camera sensors for batched rendering."
519- )
547+ if len (rgb_tensor .shape ) == 3 :
548+ # Single environment rendered - add batch dimension.
549+ rgb_tensor = rgb_tensor .unsqueeze (0 )
550+ self ._shared_metadata .image_cache [self ._idx ][:] = rgb_tensor
520551
521552
522553# ========================== Raytracer Camera Sensor ==========================
@@ -625,7 +656,10 @@ def build(self):
625656 from genesis .utils .geom import trans_quat_to_T
626657
627658 pos = torch .tensor (opts .pos , dtype = gs .tc_float , device = gs .device )
628- offset_T = trans_quat_to_T (pos , torch .tensor ([1.0 , 0.0 , 0.0 , 0.0 ], dtype = gs .tc_float , device = gs .device ))
659+ offset_T = trans_quat_to_T (
660+ pos ,
661+ torch .tensor ([1.0 , 0.0 , 0.0 , 0.0 ], dtype = gs .tc_float , device = gs .device ),
662+ )
629663 self ._camera_obj .attach (self ._link , offset_T )
630664
631665 h , w = self ._options .res [1 ], self ._options .res [0 ]
@@ -774,7 +808,12 @@ def _render_current_state(self):
774808 self ._shared_metadata .renderer .update_scene (force_render = True )
775809
776810 rgb_arr , * _ = self ._shared_metadata .renderer .render (
777- rgb = True , depth = False , segmentation = False , normal = False , antialiasing = False , force_render = True
811+ rgb = True ,
812+ depth = False ,
813+ segmentation = False ,
814+ normal = False ,
815+ antialiasing = False ,
816+ force_render = True ,
778817 )
779818
780819 # rgb_arr might be a tuple of arrays (one per camera) or a single array
0 commit comments