Camera commandsΒΆ

In addition to reads, camera parameters also support writes. These are synced to the corresponding client automatically.

 1import time
 2
 3import numpy as np
 4
 5import viser
 6import viser.transforms as tf
 7
 8server = viser.ViserServer()
 9num_frames = 20
10
11
12@server.on_client_connect
13def _(client: viser.ClientHandle) -> None:
14    """For each client that connects, we create a set of random frames + a click handler for each frame.
15
16    When a frame is clicked, we move the camera to the corresponding frame.
17    """
18
19    rng = np.random.default_rng(0)
20
21    def make_frame(i: int) -> None:
22        # Sample a random orientation + position.
23        wxyz = rng.normal(size=4)
24        wxyz /= np.linalg.norm(wxyz)
25        position = rng.uniform(-3.0, 3.0, size=(3,))
26
27        # Create a coordinate frame and label.
28        frame = client.scene.add_frame(f"/frame_{i}", wxyz=wxyz, position=position)
29        client.scene.add_label(f"/frame_{i}/label", text=f"Frame {i}")
30
31        # Move the camera when we click a frame.
32        @frame.on_click
33        def _(_):
34            T_world_current = tf.SE3.from_rotation_and_translation(
35                tf.SO3(client.camera.wxyz), client.camera.position
36            )
37            T_world_target = tf.SE3.from_rotation_and_translation(
38                tf.SO3(frame.wxyz), frame.position
39            ) @ tf.SE3.from_translation(np.array([0.0, 0.0, -0.5]))
40
41            T_current_target = T_world_current.inverse() @ T_world_target
42
43            for j in range(20):
44                T_world_set = T_world_current @ tf.SE3.exp(
45                    T_current_target.log() * j / 19.0
46                )
47
48                # We can atomically set the orientation and the position of the camera
49                # together to prevent jitter that might happen if one was set before the
50                # other.
51                with client.atomic():
52                    client.camera.wxyz = T_world_set.rotation().wxyz
53                    client.camera.position = T_world_set.translation()
54
55                client.flush()  # Optional!
56                time.sleep(1.0 / 60.0)
57
58            # Mouse interactions should orbit around the frame origin.
59            client.camera.look_at = frame.position
60
61    for i in range(num_frames):
62        make_frame(i)
63
64
65while True:
66    time.sleep(1.0)