Skip to content

Commit 4ff0661

Browse files
committed
Update video render panel of web viewer
1. Enable constant camera moving speed 2. Allow negative spline tension
1 parent 8a212e1 commit 4ff0661

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

internal/viewer/ui/render_panel.py

+35-4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(self, server: viser.ViserServer, viewer):
8383
self._viewer = viewer
8484
self._keyframes: Dict[int, Tuple[Keyframe, viser.CameraFrustumHandle]] = {}
8585
self._keyframe_counter: int = 0
86+
self._max_t = 0
8687
self._spline: Optional[viser.SceneNodeHandle] = None
8788
self._camera_edit_panel: Optional[viser.Gui3dContainerHandle] = None
8889

@@ -97,6 +98,7 @@ def __init__(self, server: viser.ViserServer, viewer):
9798
# These parameters should be overridden externally.
9899
self.loop: bool = False
99100
self.smoothness: float = 0.5 # Tension / alpha term.
101+
self.constant_speed: bool = True
100102
self.default_fov: float = 0.0
101103
self.framerate: float = 0
102104
self.duration: float = 0
@@ -276,14 +278,15 @@ def interpolate_pose_and_fov(self, normalized_t: float) -> Optional[Tuple[tf.SE3
276278
keyframe[0].override_fov_value if keyframe[0].override_fov_enabled else self.default_fov
277279
for keyframe in self._keyframes.values()
278280
],
281+
self._position_spline.grid,
279282
tcb=(self.smoothness, 0.0, 0.0),
280283
endconditions="closed" if self.loop else "natural",
281284
)
282285

283286
assert self._orientation_spline is not None
284287
assert self._position_spline is not None
285288
assert self._fov_spline is not None
286-
max_t = len(self._keyframes) if self.loop else len(self._keyframes) - 1
289+
max_t = self._max_t
287290
t = max_t * normalized_t
288291
quat = self._orientation_spline.evaluate(t)
289292
assert isinstance(quat, splines.quaternion.UnitQuaternion)
@@ -317,6 +320,15 @@ def interpolate_pose_and_fov(self, normalized_t: float) -> Optional[Tuple[tf.SE3
317320
model_poses,
318321
)
319322

323+
def get_keyframe_times(self):
324+
keyframe_positions = [keyframe[0].position for keyframe in self._keyframes.values()]
325+
if self.loop is True:
326+
keyframe_positions += keyframe_positions[:1]
327+
keyframe_distances = onp.linalg.norm(onp.diff(keyframe_positions, axis=0), axis=1)
328+
keyframe_times = onp.concatenate([[0], onp.cumsum(keyframe_distances)])
329+
330+
return keyframe_times
331+
320332
def update_spline(self) -> None:
321333
keyframes = list(self._keyframes.values())
322334
if len(keyframes) <= 1:
@@ -329,17 +341,26 @@ def update_spline(self) -> None:
329341
if num_frames <= 0:
330342
return
331343

344+
keyframe_times = None
345+
max_t = len(keyframes) if self.loop else len(keyframes) - 1
346+
if self.constant_speed is True:
347+
keyframe_times = self.get_keyframe_times()
348+
max_t = keyframe_times[-1]
349+
self._max_t = max_t
350+
332351
# Update internal splines.
333352
self._orientation_spline = splines.quaternion.KochanekBartels(
334353
[
335354
splines.quaternion.UnitQuaternion.from_unit_xyzw(onp.roll(keyframe[0].wxyz, shift=-1))
336355
for keyframe in keyframes
337356
],
357+
keyframe_times,
338358
tcb=(self.smoothness, 0.0, 0.0),
339359
endconditions="closed" if self.loop else "natural",
340360
)
341361
self._position_spline = splines.KochanekBartels(
342362
[keyframe[0].position for keyframe in keyframes],
363+
keyframe_times,
343364
tcb=(self.smoothness, 0.0, 0.0),
344365
endconditions="closed" if self.loop else "natural",
345366
)
@@ -382,9 +403,8 @@ def update_spline(self) -> None:
382403
))
383404

384405
# Update visualized spline.
385-
num_keyframes = len(keyframes) + 1 if self.loop else len(keyframes)
386406
points_array = onp.array(
387-
[self._position_spline.evaluate(t) for t in onp.linspace(0, num_keyframes - 1, num_frames)]
407+
[self._position_spline.evaluate(t) for t in onp.linspace(0, self._max_t, num_frames)]
388408
)
389409
colors_array = onp.array([colorsys.hls_to_rgb(h, 0.5, 1.0) for h in onp.linspace(0.0, 1.0, len(points_array))])
390410
self._spline = self._server.add_point_cloud(
@@ -529,7 +549,7 @@ def _(_) -> None:
529549

530550
smoothness = server.gui.add_slider(
531551
"Spline Tension",
532-
min=0.0,
552+
min=-1.0,
533553
max=1.0,
534554
initial_value=0.0,
535555
step=0.01,
@@ -541,6 +561,17 @@ def _(_) -> None:
541561
camera_path.smoothness = smoothness.value
542562
camera_path.update_spline()
543563

564+
constant_speed_checkbox = server.gui.add_checkbox(
565+
"Constant Speed",
566+
initial_value=True,
567+
hint="Maintain a constant speed for camera movement",
568+
)
569+
570+
@constant_speed_checkbox.on_update
571+
def _(_) -> None:
572+
camera_path.constant_speed = constant_speed_checkbox.value
573+
camera_path.update_spline()
574+
544575
move_checkbox = server.gui.add_checkbox(
545576
"Move keyframes",
546577
initial_value=False,

0 commit comments

Comments
 (0)