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, create GUI elements for adjusting the
15    near/far clipping planes."""
16
17    client.camera.far = 10.0
18
19    near_slider = client.gui.add_slider(
20        "Near", min=0.01, max=10.0, step=0.001, initial_value=client.camera.near
21    )
22    far_slider = client.gui.add_slider(
23        "Far", min=1, max=20.0, step=0.001, initial_value=client.camera.far
24    )
25
26    @near_slider.on_update
27    def _(_) -> None:
28        client.camera.near = near_slider.value
29
30    @far_slider.on_update
31    def _(_) -> None:
32        client.camera.far = far_slider.value
33
34
35@server.on_client_connect
36def _(client: viser.ClientHandle) -> None:
37    """For each client that connects, we create a set of random frames + a click handler for each frame.
38
39    When a frame is clicked, we move the camera to the corresponding frame.
40    """
41
42    rng = np.random.default_rng(0)
43
44    def make_frame(i: int) -> None:
45        # Sample a random orientation + position.
46        wxyz = rng.normal(size=4)
47        wxyz /= np.linalg.norm(wxyz)
48        position = rng.uniform(-3.0, 3.0, size=(3,))
49
50        # Create a coordinate frame and label.
51        frame = client.scene.add_frame(f"/frame_{i}", wxyz=wxyz, position=position)
52        client.scene.add_label(f"/frame_{i}/label", text=f"Frame {i}")
53
54        # Move the camera when we click a frame.
55        @frame.on_click
56        def _(_):
57            T_world_current = tf.SE3.from_rotation_and_translation(
58                tf.SO3(client.camera.wxyz), client.camera.position
59            )
60            T_world_target = tf.SE3.from_rotation_and_translation(
61                tf.SO3(frame.wxyz), frame.position
62            ) @ tf.SE3.from_translation(np.array([0.0, 0.0, -0.5]))
63
64            T_current_target = T_world_current.inverse() @ T_world_target
65
66            for j in range(20):
67                T_world_set = T_world_current @ tf.SE3.exp(
68                    T_current_target.log() * j / 19.0
69                )
70
71                # We can atomically set the orientation and the position of the camera
72                # together to prevent jitter that might happen if one was set before the
73                # other.
74                with client.atomic():
75                    client.camera.wxyz = T_world_set.rotation().wxyz
76                    client.camera.position = T_world_set.translation()
77
78                client.flush()  # Optional!
79                time.sleep(1.0 / 60.0)
80
81            # Mouse interactions should orbit around the frame origin.
82            client.camera.look_at = frame.position
83
84    for i in range(num_frames):
85        make_frame(i)
86
87
88while True:
89    time.sleep(1.0)