Arrow visualization

Create arrows for visualizing vectors, directions, and quantities in 3D space.

This example demonstrates viser’s arrow rendering capabilities, which are useful for visualizing directions, forces, velocities, and other vector quantities common in robotics and computer vision applications.

Use cases:

  • Perception rays in robotics and 3D sensing

  • Force vectors (contact forces, thruster forces)

  • Velocity vectors (commanded or actual velocities)

  • Axes of rotation and angular velocities

  • Coordinate frame directions

Arrows are batched into a single call for efficiency, similar to line segments. Each arrow is defined by a start point and end point, with configurable shaft radius, head radius, and head length.

Source: examples/01_scene/11_arrows.py

Arrow visualization

Code

  1import time
  2
  3import numpy as np
  4
  5import viser
  6
  7
  8def main() -> None:
  9    server = viser.ViserServer()
 10
 11    # Batched arrows.
 12    #
 13    # Create multiple arrows in a single call for efficiency.
 14    # points shape: (N, 2, 3) where points[i, 0] is the start and points[i, 1] is the end.
 15    N = 200
 16    points = np.zeros((N, 2, 3), dtype=np.float32)
 17    colors = np.zeros((N, 2, 3), dtype=np.uint8)
 18
 19    for i in range(N):
 20        # Distribute arrows in a spiral pattern
 21        theta = i * 0.3
 22        r = 1.0 + i * 0.02
 23        x = r * np.cos(theta)
 24        y = i * 0.05
 25        z = r * np.sin(theta)
 26
 27        points[i, 0] = [0, y, 0]  # start
 28        points[i, 1] = [x, y, z]  # end
 29
 30        # Color gradient from blue to red based on height
 31        color_value = int(255 * (y / (N * 0.05)))
 32        colors[i, 0] = [color_value, 0, 255 - color_value]  # shaft color
 33        colors[i, 1] = [color_value, 0, 255 - color_value]  # head color
 34
 35    server.scene.add_arrows(
 36        "/arrows/spiral",
 37        points=points,
 38        colors=colors,
 39        shaft_radius=0.02,
 40        head_radius=0.05,
 41        head_length=0.1,
 42    )
 43
 44    # Coordinate frame arrows.
 45    #
 46    # Arrows are useful for visualizing coordinate frames and axes.
 47    origin = [0, 2, 0]
 48    frame_points = np.array(
 49        [
 50            [origin, [1, 2, 0]],  # X axis
 51            [origin, [0, 3, 0]],  # Y axis
 52            [origin, [0, 2, 1]],  # Z axis
 53        ],
 54        dtype=np.float32,
 55    )
 56    frame_colors = np.array(
 57        [
 58            [[255, 0, 0], [255, 0, 0]],  # X: red
 59            [[0, 255, 0], [0, 255, 0]],  # Y: green
 60            [[0, 0, 255], [0, 0, 255]],  # Z: blue
 61        ],
 62        dtype=np.uint8,
 63    )
 64    server.scene.add_arrows(
 65        "/arrows/frame",
 66        points=frame_points,
 67        colors=frame_colors,
 68        shaft_radius=0.03,
 69        head_radius=0.08,
 70        head_length=0.15,
 71    )
 72
 73    # Force vectors example.
 74    #
 75    # Arrows can represent forces on an object. Here we show
 76    # contact forces on a simple object at position (0, 4, 0).
 77    contact_point = [0, 4, 0]
 78    force_points = np.array(
 79        [
 80            [contact_point, [0.5, 4.5, 0.3]],
 81            [contact_point, [-0.3, 4.8, -0.2]],
 82            [contact_point, [0.1, 5.2, -0.4]],
 83            [contact_point, [-0.4, 4.3, 0.5]],
 84        ],
 85        dtype=np.float32,
 86    )
 87    force_colors = np.array(
 88        [
 89            [[255, 200, 0], [255, 200, 0]],
 90            [[255, 100, 0], [255, 100, 0]],
 91            [[255, 50, 0], [255, 50, 0]],
 92            [[255, 150, 0], [255, 150, 0]],
 93        ],
 94        dtype=np.uint8,
 95    )
 96    server.scene.add_arrows(
 97        "/arrows/forces",
 98        points=force_points,
 99        colors=force_colors,
100        shaft_radius=0.04,
101        head_radius=0.1,
102        head_length=0.2,
103    )
104
105    # Uniform color arrows.
106    #
107    # For simple visualization, a single color can be applied to all arrows.
108    N_velocities = 50
109    vel_starts = np.random.normal(size=(N_velocities, 3)).astype(np.float32) * 3
110    vel_ends = (
111        vel_starts + np.random.normal(size=(N_velocities, 3)).astype(np.float32) * 0.5
112    )
113    velocity_points = np.stack([vel_starts, vel_ends], axis=1)
114
115    server.scene.add_arrows(
116        "/arrows/velocities",
117        points=velocity_points,
118        colors=(100, 200, 255),  # Uniform light blue
119        shaft_radius=0.015,
120        head_radius=0.04,
121        head_length=0.08,
122    )
123
124    while True:
125        time.sleep(10.0)
126
127
128if __name__ == "__main__":
129    main()