Creating Visualization Markers#
Visualization markers render debug geometry (frames, arrows, spheres, custom meshes) over the
scene through markers.VisualizationMarkers. Markers are display-only: they carry no
physics and do not affect the simulation.
For plain points, lines, and splines, Isaac Sim’s own isaacsim.util.debug_draw extension
is lighter-weight. Use VisualizationMarkers when you need more complex shapes.
Supported on Kit, Newton GL, Rerun, and Viser; not yet on Newton RTX. See Visualization for enabling markers on a given visualizer.
Quick Start#
This guide is accompanied by markers.py in IsaacLab/scripts/demos.
uv run --extra isaacsim python scripts/demos/markers.py
./isaaclab.sh -p scripts/demos/markers.py
Pass --visualizer newton_gl (or another supported backend) to switch visualizers; defaults
to kit.
Every marker prototype from the demo script, arranged in a grid. Each column rotates in place and periodically rolls forward to the next prototype.#
To stop, close the window or press Ctrl+C.
Code for markers.py
1# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""This script demonstrates different types of markers.
7
8.. code-block:: bash
9
10 # Usage with default PhysX physics and default kit visualizer.
11 uv run python scripts/demos/markers.py
12
13"""
14
15"""Parse CLI first so we can decide whether to launch Isaac Sim Kit."""
16
17import argparse
18from typing import TYPE_CHECKING
19
20from isaaclab.app import add_launcher_args, launch_simulation
21
22# add argparse arguments
23parser = argparse.ArgumentParser(
24 description="This script demonstrates different types of markers.",
25 conflict_handler="resolve",
26)
27parser.add_argument("--physics", default="isaacsim_physx", choices=["isaacsim_physx"], help="Physics backend.")
28add_launcher_args(parser)
29parser.set_defaults(visualizer=["kit"])
30args_cli = parser.parse_args()
31
32import torch
33
34import isaaclab.sim as sim_utils
35
36##
37# Pre-defined configs
38##
39from isaaclab.markers.visualization_markers_cfg import VisualizationMarkersCfg
40from isaaclab.physics import PhysicsCfg
41from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR, ISAACLAB_NUCLEUS_DIR
42from isaaclab.utils.math import quat_from_angle_axis
43
44if TYPE_CHECKING:
45 from isaaclab.markers import VisualizationMarkers
46
47
48def define_markers() -> "VisualizationMarkers":
49 """Define markers with various different shapes."""
50 marker_cfg = VisualizationMarkersCfg(
51 prim_path="/Visuals/myMarkers",
52 markers={
53 "frame": sim_utils.UsdFileCfg(
54 usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/UIElements/frame_prim.usd",
55 scale=(0.5, 0.5, 0.5),
56 ),
57 "arrow_x": sim_utils.UsdFileCfg(
58 usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/UIElements/arrow_x.usd",
59 scale=(1.0, 0.5, 0.5),
60 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 1.0)),
61 ),
62 "cube": sim_utils.CuboidCfg(
63 size=(1.0, 1.0, 1.0),
64 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 0.0)),
65 ),
66 "sphere": sim_utils.SphereCfg(
67 radius=0.5,
68 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0)),
69 ),
70 "cylinder": sim_utils.CylinderCfg(
71 radius=0.5,
72 height=1.0,
73 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 1.0)),
74 ),
75 "cone": sim_utils.ConeCfg(
76 radius=0.5,
77 height=1.0,
78 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 1.0, 0.0)),
79 ),
80 "mesh": sim_utils.UsdFileCfg(
81 usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Blocks/DexCube/dex_cube_instanceable.usd",
82 scale=(10.0, 10.0, 10.0),
83 ),
84 "mesh_recolored": sim_utils.UsdFileCfg(
85 usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Blocks/DexCube/dex_cube_instanceable.usd",
86 scale=(10.0, 10.0, 10.0),
87 visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.25, 0.0)),
88 ),
89 "robot_mesh": sim_utils.UsdFileCfg(
90 usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/ANYbotics/ANYmal-C/anymal_c.usd",
91 scale=(2.0, 2.0, 2.0),
92 visual_material=sim_utils.GlassMdlCfg(glass_color=(0.0, 0.1, 0.0)),
93 ),
94 },
95 )
96 return marker_cfg.class_type(marker_cfg)
97
98
99def main():
100 """Main function."""
101 with launch_simulation(cfg=PhysicsCfg(), launcher_args=args_cli) as physics_cfg:
102 # Load kit helper
103 sim_cfg = sim_utils.SimulationCfg(dt=0.01, device=args_cli.device, physics=physics_cfg)
104 sim = sim_utils.SimulationContext(sim_cfg)
105 # Set main camera
106 sim.set_camera_view([0.0, 18.0, 12.0], [0.0, 3.0, 0.0])
107
108 # Spawn things into stage
109 # Lights
110 cfg = sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
111 cfg.func("/World/Light", cfg)
112
113 # create markers
114 my_visualizer = define_markers()
115
116 # define a grid of positions where the markers should be placed
117 num_markers_per_type = 5
118 grid_spacing = 2.0
119 # Calculate the half-width and half-height
120 half_width = (num_markers_per_type - 1) / 2.0
121 half_height = (my_visualizer.num_prototypes - 1) / 2.0
122 # Create the x and y ranges centered around the origin
123 x_range = torch.arange(-half_width * grid_spacing, (half_width + 1) * grid_spacing, grid_spacing)
124 y_range = torch.arange(-half_height * grid_spacing, (half_height + 1) * grid_spacing, grid_spacing)
125 # Create the grid
126 x_grid, y_grid = torch.meshgrid(x_range, y_range, indexing="ij")
127 x_grid = x_grid.reshape(-1)
128 y_grid = y_grid.reshape(-1)
129 z_grid = torch.zeros_like(x_grid)
130 # marker locations
131 marker_locations = torch.stack([x_grid, y_grid, z_grid], dim=1)
132 marker_indices = torch.arange(my_visualizer.num_prototypes).repeat(num_markers_per_type)
133
134 # Play the simulator
135 sim.reset()
136 # Now we are ready!
137 print("[INFO]: Setup complete...")
138
139 # Yaw angle
140 yaw = torch.zeros_like(marker_locations[:, 0])
141 # Step while a visualizer window is still open (or none exist, e.g. headless); works for kit and newton.
142 while sim.is_headless_or_exist_active_visualizer():
143 # rotate the markers around the z-axis for visualization
144 marker_orientations = quat_from_angle_axis(yaw, torch.tensor([0.0, 0.0, 1.0]))
145 # visualize
146 my_visualizer.visualize(marker_locations, marker_orientations, marker_indices=marker_indices)
147 # roll corresponding indices to show how marker prototype can be changed
148 if yaw[0].item() % (0.5 * torch.pi) < 0.01:
149 marker_indices = torch.roll(marker_indices, 1)
150 # perform step
151 sim.step()
152 # increment yaw
153 yaw += 0.01
154
155
156if __name__ == "__main__":
157 # run the main function
158 main()
Configuring markers#
VisualizationMarkersCfg takes:
prim_path: prim path where the markerUsdGeom.PointInstanceris created.markers: a dict of marker prototypes. The key names the prototype; the value is its spawn config (anySpawnerCfg, including USD file references).
Note
Physics properties on a marker prototype’s spawn config are stripped on creation, since markers are not simulated.
marker_cfg = VisualizationMarkersCfg(
prim_path="/Visuals/myMarkers",
markers={
"frame": sim_utils.UsdFileCfg(
usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/UIElements/frame_prim.usd",
scale=(0.5, 0.5, 0.5),
),
"arrow_x": sim_utils.UsdFileCfg(
usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/UIElements/arrow_x.usd",
scale=(1.0, 0.5, 0.5),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 1.0)),
),
"cube": sim_utils.CuboidCfg(
size=(1.0, 1.0, 1.0),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 0.0)),
),
"sphere": sim_utils.SphereCfg(
radius=0.5,
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0)),
),
"cylinder": sim_utils.CylinderCfg(
radius=0.5,
height=1.0,
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 1.0)),
),
"cone": sim_utils.ConeCfg(
radius=0.5,
height=1.0,
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 1.0, 0.0)),
),
"mesh": sim_utils.UsdFileCfg(
usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Blocks/DexCube/dex_cube_instanceable.usd",
scale=(10.0, 10.0, 10.0),
),
"mesh_recolored": sim_utils.UsdFileCfg(
usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Blocks/DexCube/dex_cube_instanceable.usd",
scale=(10.0, 10.0, 10.0),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.25, 0.0)),
),
"robot_mesh": sim_utils.UsdFileCfg(
usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/ANYbotics/ANYmal-C/anymal_c.usd",
scale=(2.0, 2.0, 2.0),
visual_material=sim_utils.GlassMdlCfg(glass_color=(0.0, 0.1, 0.0)),
),
},
)
return marker_cfg.class_type(marker_cfg)
Drawing markers#
visualize() sets marker poses and, optionally, which
prototype each marker instance uses via marker_indices.
marker_orientations = quat_from_angle_axis(yaw, torch.tensor([0.0, 0.0, 1.0]))
# visualize
my_visualizer.visualize(marker_locations, marker_orientations, marker_indices=marker_indices)
Arguments left as None keep their previous value. Passing a different number of rows than
the last call resizes the marker instance count. See
visualize()’s docstring for the full argument list
(translations, orientations, scales, marker_indices, environment_ids).
Markers in practice#
Markers are commonly used to debug per-environment state during training, such as commanded vs. current velocity, or contact events:
Velocity command (green) and current velocity (blue) arrow markers on an AnymalD robot.
Joint arrow markers on a Franka arm, with contact sensor markers on a cube.
See also#
Visualization: enabling markers per visualizer, and other visualizer features
Recording Video: recording a marker-annotated scene to video