Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions genesis/engine/sensors/imu.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def _draw_debug(self, context: "RasterizerContext", buffer_updates: dict[str, np
data = self.read(env_idx)
acc_vec = data.lin_acc.reshape((3,)) * self._options.debug_acc_scale
gyro_vec = data.ang_vel.reshape((3,)) * self._options.debug_gyro_scale
mag_vec = data.mag.reshape((3,)) * self._options.debug_mag_scale # added mag debug
mag_vec = data.mag.reshape((3,)) * self._options.debug_mag_scale

# transform from local frame to world frame
offset_quat = transform_quat_by_quat(self.quat_offset, quat)
Expand All @@ -286,8 +286,8 @@ def _draw_debug(self, context: "RasterizerContext", buffer_updates: dict[str, np
self.debug_objects += filter(
None,
(
context.draw_debug_arrow(pos=pos, vec=acc_vec, color=self._options.debug_acc_color),
context.draw_debug_arrow(pos=pos, vec=gyro_vec, color=self._options.debug_gyro_color),
context.draw_debug_arrow(pos=pos, vec=mag_vec, color=self._options.debug_mag_color),
context.draw_debug_arrow(pos=pos, vec=acc_vec, radius=0.006, color=self._options.debug_acc_color),
context.draw_debug_arrow(pos=pos, vec=gyro_vec, radius=0.0055, color=self._options.debug_gyro_color),
context.draw_debug_arrow(pos=pos, vec=mag_vec, radius=0.005, color=self._options.debug_mag_color),
),
)
46 changes: 31 additions & 15 deletions genesis/ext/pyrender/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@


pyglet.options["shadow_window"] = False
pyglet.options["dpi_scaling"] = "real"


MODULE_DIR = os.path.dirname(__file__)
Expand Down Expand Up @@ -366,9 +367,7 @@ def __init__(
#######################################################################
# Initialize OpenGL context and renderer
#######################################################################
self._renderer = Renderer(
self._viewport_size[0], self._viewport_size[1], context.jit, self.render_flags["point_size"]
)
self._renderer = Renderer(*self._viewport_size, context.jit, self.render_flags["point_size"])
self._is_active = True

# Starting the viewer would raise an exception if the OpenGL context is invalid for some reason. This exception
Expand Down Expand Up @@ -654,12 +653,18 @@ def on_close(self):
super().close()
except Exception:
pass
finally:
try:
super().on_close()
try:
pyglet.app.exit()
except Exception:
pass
except Exception:
pass
try:
pyglet.app.exit()
except Exception:
pass
try:
pyglet.app.platform_event_loop.stop()
except Exception:
pass

self._offscreen_semaphore.release()

Expand Down Expand Up @@ -788,8 +793,8 @@ def on_resize(self, width: int, height: int) -> EVENT_HANDLE_STATE:

self._viewport_size = (width, height)
self._trackball.resize(self._viewport_size)
self._renderer.viewport_width = self._viewport_size[0]
self._renderer.viewport_height = self._viewport_size[1]
self._renderer.viewport_width = width
self._renderer.viewport_height = height
self.on_draw()

def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> EVENT_HANDLE_STATE:
Expand Down Expand Up @@ -998,9 +1003,9 @@ def _render(self, camera_node=None, renderer=None, normal=False):
elif self.render_flags["all_solid"]:
flags |= RenderFlags.ALL_SOLID

if self.render_flags["shadows"]:
if self.render_flags["shadows"] and not self._is_software:
flags |= RenderFlags.SHADOWS_ALL
if self.render_flags["plane_reflection"]:
if self.render_flags["plane_reflection"] and not self._is_software:
flags |= RenderFlags.REFLECTIVE_FLOOR
if self.render_flags["env_separate_rigid"]:
flags |= RenderFlags.ENV_SEPARATE
Expand Down Expand Up @@ -1149,12 +1154,16 @@ def start(self, auto_refresh=True):
confs.insert(0, conf)
raise

# Determine if software emulation is being used
glinfo = self.context.get_info()
renderer = glinfo.get_renderer()
self._is_software = any(e in renderer for e in ("llvmpipe", "Apple Software Renderer"))

# Run the entire rendering pipeline first without window, to make sure that all kernels are compiled
self.refresh()

# At this point, we are all set to display the graphical window if requested
if not pyglet.options["headless"]:
self.set_visible(True)
# At this point, we are all set to display the graphical window
self.set_visible(True)

# Run the entire rendering pipeline once again, as a final validation that everything is fine
self.refresh()
Expand Down Expand Up @@ -1202,6 +1211,13 @@ def start(self, auto_refresh=True):
if not self._initialized_event.is_set():
self._initialized_event.set()

gs.logger.debug(f"Using interactive viewer OpenGL device: {renderer}")
if self._is_software:
gs.logger.info(
"Software rendering context detected. Shadows and plane reflection not supported. Beware rendering "
"will be extremely slow."
)

if auto_refresh:
while self._is_active:
try:
Expand Down
14 changes: 7 additions & 7 deletions genesis/options/sensors/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ class IMU(RigidSensorOptionsMixin, NoisySensorOptionsMixin, SensorOptions):
mag_random_walk : tuple[float, float, float]
The standard deviation of the bias drift for each axis of the magnetometer.
debug_acc_color : float, optional
The rgba color of the debug acceleration arrow. Defaults to (0.0, 1.0, 1.0, 0.5).
The rgba color of the debug acceleration arrow. Defaults to (1.0, 0.0, 0.0, 0.6).
debug_acc_scale: float, optional
The scale factor for the debug acceleration arrow. Defaults to 0.01.
debug_gyro_color : float, optional
The rgba color of the debug gyroscope arrow. Defaults to (1.0, 1.0, 0.0, 0.5).
The rgba color of the debug gyroscope arrow. Defaults to (0.0, 1.0, 0.0, 0.6).
debug_gyro_scale: float, optional
The scale factor for the debug gyroscope arrow. Defaults to 0.01.
debug_mag_color : float, optional
The rgba color of the debug magnetometer arrow. Defaults to (1.0, 1.0, 0.0, 0.5).
The rgba color of the debug magnetometer arrow. Defaults to (0.0, 0.0, 1.0, 0.6).
debug_mag_scale: float, optional
The scale factor for the debug magnetometer arrow. Defaults to 0.01.
"""
Expand All @@ -261,12 +261,12 @@ class IMU(RigidSensorOptionsMixin, NoisySensorOptionsMixin, SensorOptions):
mag_random_walk: MaybeTuple3FType = 0.0
magnetic_field: MaybeTuple3FType = (0.0, 0.0, 0.5)

debug_acc_color: tuple[float, float, float, float] = (0.0, 1.0, 1.0, 0.5)
debug_acc_color: tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.6)
debug_acc_scale: float = 0.01
debug_gyro_color: tuple[float, float, float, float] = (1.0, 1.0, 0.0, 0.5)
debug_gyro_color: tuple[float, float, float, float] = (0.0, 1.0, 0.0, 0.6)
debug_gyro_scale: float = 0.01
debug_mag_color: tuple[float, float, float, float] = (0.0, 0.0, 1.0, 0.5)
debug_mag_scale: float = 2.0
debug_mag_color: tuple[float, float, float, float] = (0.0, 0.0, 1.0, 0.6)
debug_mag_scale: float = 0.5

def model_post_init(self, _):
self._validate_cross_axis_coupling(self.acc_cross_axis_coupling)
Expand Down
4 changes: 0 additions & 4 deletions genesis/vis/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ def build(self, scene):

gs.logger.info(f"Viewer created. Resolution: ~<{self._res[0]}×{self._res[1]}>~, max_FPS: ~<{self._max_FPS}>~.")

glinfo = self._pyrender_viewer.context.get_info()
renderer = glinfo.get_renderer()
gs.logger.debug(f"Using interactive viewer OpenGL device: {renderer}")

self._is_built = True

def run(self):
Expand Down
24 changes: 13 additions & 11 deletions tests/test_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,17 +1036,21 @@ def test_draw_debug(renderer, show_viewer):
@pytest.mark.parametrize("n_envs", [0, 2])
@pytest.mark.parametrize("renderer_type", [RENDERER_TYPE.RASTERIZER])
@pytest.mark.skipif(not IS_INTERACTIVE_VIEWER_AVAILABLE, reason="Interactive viewer not supported on this platform.")
def test_sensors_draw_debug(n_envs, renderer, png_snapshot):
def test_sensors_draw_debug(n_envs, renderer_type, renderer, png_snapshot):
"""Test that sensor debug drawing works correctly and renders visible debug elements."""
scene = gs.Scene(
viewer_options=gs.options.ViewerOptions(
camera_pos=(2.0, 2.0, 2.0),
camera_lookat=(0.0, 0.0, 0.2),
# Force screen-independent low-quality resolution when running unit tests for consistency
res=(640, 480),
res=(480, 320),
# Enable running in background thread if supported by the platform
run_in_thread=(sys.platform == "linux"),
),
vis_options=gs.options.VisOptions(
# Disable shadows systematically for Rasterizer because they are forcibly disabled on CPU backend anyway
shadow=(renderer_type != RENDERER_TYPE.RASTERIZER),
),
profiling_options=gs.options.ProfilingOptions(
show_FPS=False,
),
Expand Down Expand Up @@ -1143,19 +1147,13 @@ def test_sensors_draw_debug(n_envs, renderer, png_snapshot):
if renderer == "Apple Software Renderer":
pytest.xfail("Tile ground colors are altered on Apple Software Renderer.")

try:
assert rgb_array_to_png_bytes(rgb_arr) == png_snapshot
except AssertionError:
# TODO: Need to investigate root cause and either fix rendering consistency
if sys.platform == "linux" and gs.use_ndarray:
pytest.xfail("Sensor debug drawing produces inconsistent results on Linux with static array mode.")
raise
assert rgb_array_to_png_bytes(rgb_arr) == png_snapshot


@pytest.mark.required
@pytest.mark.parametrize("renderer_type", [RENDERER_TYPE.RASTERIZER])
@pytest.mark.skipif(not IS_INTERACTIVE_VIEWER_AVAILABLE, reason="Interactive viewer not supported on this platform.")
def test_interactive_viewer_key_press(tmp_path, monkeypatch, renderer, png_snapshot):
def test_interactive_viewer_key_press(renderer_type, tmp_path, monkeypatch, renderer, png_snapshot):
IMAGE_FILENAME = tmp_path / "screenshot.png"

# Mock 'get_save_filename' to avoid poping up an interactive dialog
Expand All @@ -1181,13 +1179,17 @@ def on_key_press(self, symbol: int, modifiers: int):
scene = gs.Scene(
viewer_options=gs.options.ViewerOptions(
# Force screen-independent low-quality resolution when running unit tests for consistency
res=(640, 480),
res=(480, 320),
# Enable running in background thread if supported by the platform.
# Note that windows is not supported because it would trigger the following exception if some previous tests
# was only using rasterizer without interactive viewer:
# 'EventLoop.run() must be called from the same thread that imports pyglet.app'.
run_in_thread=(sys.platform == "linux"),
),
vis_options=gs.options.VisOptions(
# Disable shadows systematically for Rasterizer because they are forcibly disabled on CPU backend anyway
shadow=(renderer_type != RENDERER_TYPE.RASTERIZER),
),
renderer=renderer,
show_viewer=True,
show_FPS=False,
Expand Down
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
DEFAULT_BRANCH_NAME = "main"

HUGGINGFACE_ASSETS_REVISION = "ca29b66018b449a37738257a3a76a78529d29bcc"
HUGGINGFACE_SNAPSHOT_REVISION = "0cf1780dd70b67dc426023cd97738037f0d834e3"
HUGGINGFACE_SNAPSHOT_REVISION = "137990d0632610c575a3ac3a769031f632454254"

MESH_EXTENSIONS = (".mtl", *MESH_FORMATS, *GLTF_FORMATS, *USD_FORMATS)
IMAGE_EXTENSIONS = (".png", ".jpg")
Expand Down
Loading