From ba0d1e1668de32c3b44d34c44f2e8060dcfee269 Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:46:48 +0530 Subject: [PATCH 1/6] [FEATURE] Add draw_debug_pyramid and draw_debug_trajectory to scene API --- genesis/engine/scene.py | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/genesis/engine/scene.py b/genesis/engine/scene.py index 9b179fe163..3223f3ebc7 100644 --- a/genesis/engine/scene.py +++ b/genesis/engine/scene.py @@ -1249,6 +1249,61 @@ def draw_debug_points(self, poss, colors=(1.0, 0.0, 0.0, 0.5)): """ with self._visualizer.viewer_lock: return self._visualizer.context.draw_debug_points(poss, colors) + + @gs.assert_built + def draw_debug_pyramid(self, T, base_width=0.05, base_height=0.05, height=0.05, color=(1.0, 1.0, 1.0, 0.5)): + """ + Draws a pyramid in the scene for visualization. + + Parameters + ---------- + T : array_like, shape (4, 4) + The transformation matrix of the pyramid. + base_width : float, optional + The width of the pyramid base. + base_height : float, optional + The height of the pyramid base. + height : float, optional + The height of the pyramid. + color : array_like, shape (4,), optional + The color of the pyramid in RGBA format. + + Returns + ------- + nodes : list + List of created debug line objects. + """ + with self._visualizer.viewer_lock: + return self._visualizer.context.draw_debug_pyramid(T, base_width, base_height, height, color) + + @gs.assert_built + def draw_debug_trajectory(self, poss, radius=0.002, color=(1.0, 0.5, 0.0, 0.8)): + """ + Draws a trajectory as a series of connected lines in the scene for visualization. + + Parameters + ---------- + poss : array_like, shape (N, 3) + The positions of the trajectory points. + radius : float, optional + The radius of the trajectory lines. + color : array_like, shape (4,), optional + The color of the trajectory in RGBA format. + + Returns + ------- + nodes : list + List of created debug line objects. + """ + nodes = [] + with self._visualizer.viewer_lock: + for i in range(len(poss) - 1): + node = self._visualizer.context.draw_debug_line( + poss[i], poss[i + 1], radius, color + ) + nodes.append(node) + return nodes + @gs.assert_built def draw_debug_path(self, qposs, entity, link_idx=-1, density=0.3, frame_scaling=1.0): From 7852c59c2e8c1e75a123e2aad45aaaab44c7d9fa Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:59:48 +0530 Subject: [PATCH 2/6] [FEATURE] Add draw_debug_pyramid and draw_debug_trajectory to scene API with documentation --- genesis/engine/scene.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/genesis/engine/scene.py b/genesis/engine/scene.py index 3223f3ebc7..123f62203e 100644 --- a/genesis/engine/scene.py +++ b/genesis/engine/scene.py @@ -1249,7 +1249,7 @@ def draw_debug_points(self, poss, colors=(1.0, 0.0, 0.0, 0.5)): """ with self._visualizer.viewer_lock: return self._visualizer.context.draw_debug_points(poss, colors) - + @gs.assert_built def draw_debug_pyramid(self, T, base_width=0.05, base_height=0.05, height=0.05, color=(1.0, 1.0, 1.0, 0.5)): """ @@ -1275,7 +1275,7 @@ def draw_debug_pyramid(self, T, base_width=0.05, base_height=0.05, height=0.05, """ with self._visualizer.viewer_lock: return self._visualizer.context.draw_debug_pyramid(T, base_width, base_height, height, color) - + @gs.assert_built def draw_debug_trajectory(self, poss, radius=0.002, color=(1.0, 0.5, 0.0, 0.8)): """ @@ -1298,13 +1298,10 @@ def draw_debug_trajectory(self, poss, radius=0.002, color=(1.0, 0.5, 0.0, 0.8)): nodes = [] with self._visualizer.viewer_lock: for i in range(len(poss) - 1): - node = self._visualizer.context.draw_debug_line( - poss[i], poss[i + 1], radius, color - ) + node = self._visualizer.context.draw_debug_line(poss[i], poss[i + 1], radius, color) nodes.append(node) return nodes - @gs.assert_built def draw_debug_path(self, qposs, entity, link_idx=-1, density=0.3, frame_scaling=1.0): """ From adfc954f80be86fa3c60e095bcf7860245ac5cd7 Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:06:14 +0530 Subject: [PATCH 3/6] [MISC] Add documentation for draw_debug_pyramid and draw_debug_trajectory --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index d92ab5c51f..3587e938e1 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit d92ab5c51f12d898a522bb0fa814ba56b3ed3181 +Subproject commit 3587e938e1e86c86b6a7ef8463aedc7b55c08176 From a0eae69de00f986b1f5ec5e6c4554b43df8cafdd Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:05:25 +0530 Subject: [PATCH 4/6] [FEATURE] Add draw_debug_frustum and draw_debug_trajectory to scene API with documentation --- doc | 2 +- genesis/engine/scene.py | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/doc b/doc index 3587e938e1..8764c4c5ac 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 3587e938e1e86c86b6a7ef8463aedc7b55c08176 +Subproject commit 8764c4c5ac37ab3e287997adf405a06abd10a4cc diff --git a/genesis/engine/scene.py b/genesis/engine/scene.py index 123f62203e..855d7d815d 100644 --- a/genesis/engine/scene.py +++ b/genesis/engine/scene.py @@ -1251,30 +1251,28 @@ def draw_debug_points(self, poss, colors=(1.0, 0.0, 0.0, 0.5)): return self._visualizer.context.draw_debug_points(poss, colors) @gs.assert_built - def draw_debug_pyramid(self, T, base_width=0.05, base_height=0.05, height=0.05, color=(1.0, 1.0, 1.0, 0.5)): + def draw_debug_frustum(self, camera, color=(1.0, 1.0, 1.0, 0.3)): """ - Draws a pyramid in the scene for visualization. + Draws a camera frustum in the scene for visualization. Parameters ---------- - T : array_like, shape (4, 4) - The transformation matrix of the pyramid. - base_width : float, optional - The width of the pyramid base. - base_height : float, optional - The height of the pyramid base. - height : float, optional - The height of the pyramid. + camera : Camera + The camera object whose frustum will be visualized. Works for any + camera including sensor cameras. color : array_like, shape (4,), optional - The color of the pyramid in RGBA format. + The color of the frustum in RGBA format. Returns ------- - nodes : list - List of created debug line objects. + node : genesis.ext.pyrender.mesh.Mesh + The created debug object. """ with self._visualizer.viewer_lock: - return self._visualizer.context.draw_debug_pyramid(T, base_width, base_height, height, color) + import genesis.utils.mesh as mu + + mesh = mu.create_camera_frustum(camera, color) + return self._visualizer.context.draw_debug_mesh(mesh) @gs.assert_built def draw_debug_trajectory(self, poss, radius=0.002, color=(1.0, 0.5, 0.0, 0.8)): From 667ae85989513526779321cac347c9ecb52f2d76 Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Mon, 23 Mar 2026 21:09:42 +0530 Subject: [PATCH 5/6] fix: ruff formatting --- genesis/engine/scene.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/genesis/engine/scene.py b/genesis/engine/scene.py index 855d7d815d..0715f59ba8 100644 --- a/genesis/engine/scene.py +++ b/genesis/engine/scene.py @@ -42,6 +42,7 @@ from genesis.utils.misc import tensor_to_array, sanitize_index from genesis.vis import Visualizer from genesis.utils.warnings import warn_once +import genesis.utils.mesh as mu if TYPE_CHECKING: from genesis.engine.entities.base_entity import Entity @@ -1269,8 +1270,6 @@ def draw_debug_frustum(self, camera, color=(1.0, 1.0, 1.0, 0.3)): The created debug object. """ with self._visualizer.viewer_lock: - import genesis.utils.mesh as mu - mesh = mu.create_camera_frustum(camera, color) return self._visualizer.context.draw_debug_mesh(mesh) From 06689c2ed196fb824d0b950de8df05ca56fedd7c Mon Sep 17 00:00:00 2001 From: Mehak261124 <145124929+Mehak261124@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:04:12 +0530 Subject: [PATCH 6/6] [FEATURE] Add unit tests for draw_debug_frustum and draw_debug_trajectory --- tests/test_render.py | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/test_render.py b/tests/test_render.py index cae1f06ea4..c36e080edc 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -1041,6 +1041,70 @@ def test_draw_debug(renderer, show_viewer): assert_allclose(np.std(rgb_array.reshape((-1, 3)), axis=0), 0.0, tol=gs.EPS) +@pytest.mark.required +@pytest.mark.parametrize("renderer_type", [RENDERER_TYPE.RASTERIZER]) +def test_draw_debug_frustum_and_trajectory(renderer, show_viewer): + """Test that draw_debug_frustum and draw_debug_trajectory render visible content.""" + if "GS_DISABLE_OFFSCREEN_MARKERS" in os.environ: + pytest.skip("Offscreen rendering of markers is forcibly disabled. Skipping...") + + scene = gs.Scene( + renderer=renderer, + show_viewer=show_viewer, + show_FPS=False, + ) + cam = scene.add_camera( + pos=(3.5, 0.5, 2.5), + lookat=(0.0, 0.0, 0.5), + res=(640, 640), + debug=True, + GUI=show_viewer, + ) + # Add sensor_cam BEFORE build + sensor_cam = scene.add_camera( + res=(640, 480), + pos=(1.0, 0.0, 1.0), + lookat=(0.0, 0.0, 0.0), + fov=45, + GUI=False, + ) + scene.build() + + # Verify scene is initially blank + rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False) + assert_allclose(np.std(rgb_array.reshape((-1, 3)), axis=0), 0.0, tol=gs.EPS) + + # Test draw_debug_frustum + scene.draw_debug_frustum(sensor_cam, color=(0.0, 1.0, 0.0, 0.5)) + scene.visualizer.update() + + rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False) + rgb_array_flat = rgb_array.reshape((-1, 3)).astype(np.int32) + assert (np.std(rgb_array_flat, axis=0) > 10.0).any() + + # Clear and verify blank again + scene.clear_debug_objects() + scene.visualizer.update() + rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False) + assert_allclose(np.std(rgb_array.reshape((-1, 3)), axis=0), 0.0, tol=gs.EPS) + + # Test draw_debug_trajectory + t = np.linspace(0, 2 * np.pi, 50) + positions = np.column_stack([np.cos(t), np.sin(t), np.ones_like(t) * 0.5]) + scene.draw_debug_trajectory(positions, radius=0.01, color=(1.0, 0.5, 0.0, 1.0)) + scene.visualizer.update() + + rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False) + rgb_array_flat = rgb_array.reshape((-1, 3)).astype(np.int32) + assert (np.std(rgb_array_flat, axis=0) > 10.0).any() + + # Clear and verify blank again + scene.clear_debug_objects() + scene.visualizer.update() + rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False) + assert_allclose(np.std(rgb_array.reshape((-1, 3)), axis=0), 0.0, tol=gs.EPS) + + @pytest.mark.slow # ~150s @pytest.mark.required @pytest.mark.parametrize("n_envs", [0, 2])