@@ -1326,86 +1326,106 @@ def _(event: viser.GuiEvent) -> None:
13261326 client = event .client
13271327 assert client is not None
13281328
1329- # enter into preview render mode
1330- render_tab_state .preview_render = True
1331- maybe_pose_and_fov_rad = compute_and_update_preview_camera_state ()
1332- if maybe_pose_and_fov_rad is None :
1333- remove_preview_camera ()
1334- return
1335- if len (maybe_pose_and_fov_rad ) == 3 : # Time is enabled.
1336- pose , fov , time = maybe_pose_and_fov_rad
1337- else :
1338- pose , fov = maybe_pose_and_fov_rad
1339- del fov
1329+ video_outfile = output_dir / "videos" / f"traj_{ trajectory_name_text .value } .mp4"
13401330
1341- # Hide all scene nodes when we're previewing the render.
1342- server .scene .set_global_visibility (False )
1331+ def dump_video () -> None :
1332+ # enter into preview render mode
1333+ render_tab_state .preview_render = True
1334+ maybe_pose_and_fov_rad = compute_and_update_preview_camera_state ()
1335+ if maybe_pose_and_fov_rad is None :
1336+ remove_preview_camera ()
1337+ return
1338+ if len (maybe_pose_and_fov_rad ) == 3 : # Time is enabled.
1339+ pose , fov , time = maybe_pose_and_fov_rad
1340+ else :
1341+ pose , fov = maybe_pose_and_fov_rad
1342+ del fov
1343+
1344+ # Hide all scene nodes when we're previewing the render.
1345+ server .scene .set_global_visibility (False )
1346+
1347+ # Back up and then set camera poses.
1348+ with server .atomic ():
1349+ for client in server .get_clients ().values ():
1350+ camera_pose_backup_from_id [client .client_id ] = (
1351+ client .camera .position ,
1352+ client .camera .look_at ,
1353+ client .camera .up_direction ,
1354+ )
1355+ client .camera .wxyz = pose .rotation ().wxyz
1356+ client .camera .position = pose .translation ()
1357+
1358+ # disable all the trajectory control widgets
1359+ handles_to_disable = list (handles .values ()) + list (extra_handles .values ())
1360+ original_disabled = [handle .disabled for handle in handles_to_disable ]
1361+ for handle in handles_to_disable :
1362+ handle .disabled = True
1363+
1364+ def dump () -> None :
1365+ os .makedirs (output_dir / "videos" , exist_ok = True )
1366+ writer = imageio .get_writer (video_outfile , fps = framerate_number .value )
1367+ max_frame = int (framerate_number .value * duration_number .value )
1368+ assert max_frame > 0 and preview_frame_slider is not None
1369+ preview_frame_slider .value = 0
1370+ for _ in range (max_frame ):
1371+ preview_frame_slider .value = (
1372+ preview_frame_slider .value + 1
1373+ ) % max_frame
1374+ # should we use get_render here?
1375+ image = client .camera .get_render (
1376+ height = render_res_vec2 .value [1 ],
1377+ width = render_res_vec2 .value [0 ],
1378+ )
1379+ writer .append_data (image )
1380+ writer .close ()
1381+ print (f"Video saved to { video_outfile } " )
1382+
1383+ dump_thread = threading .Thread (target = dump )
1384+ dump_thread .start ()
1385+ dump_thread .join ()
1386+
1387+ # restore the original disabled state
1388+ for handle , original_disabled in zip (handles_to_disable , original_disabled ):
1389+ handle .disabled = original_disabled
1390+
1391+ # exit preview render mode
1392+ render_tab_state .preview_render = False
1393+
1394+ # Revert camera poses.
1395+ with server .atomic ():
1396+ for client in server .get_clients ().values ():
1397+ if client .client_id not in camera_pose_backup_from_id :
1398+ continue
1399+ cam_position , cam_look_at , cam_up = camera_pose_backup_from_id .pop (
1400+ client .client_id
1401+ )
1402+ client .camera .position = cam_position
1403+ client .camera .look_at = cam_look_at
1404+ client .camera .up_direction = cam_up
1405+ client .flush ()
13431406
1344- # Back up and then set camera poses.
1345- with server .atomic ():
1346- for client in server .get_clients ().values ():
1347- camera_pose_backup_from_id [client .client_id ] = (
1348- client .camera .position ,
1349- client .camera .look_at ,
1350- client .camera .up_direction ,
1351- )
1352- client .camera .wxyz = pose .rotation ().wxyz
1353- client .camera .position = pose .translation ()
1407+ # Un-hide scene nodes.
1408+ server .scene .set_global_visibility (True )
13541409
1355- # disable all the trajectory control widgets
1356- handles_to_disable = list (handles .values ()) + list (extra_handles .values ())
1357- original_disabled = [handle .disabled for handle in handles_to_disable ]
1358- for handle in handles_to_disable :
1359- handle .disabled = True
1360-
1361- def dump () -> None :
1362- os .makedirs (output_dir / "videos" , exist_ok = True )
1363- writer = imageio .get_writer (
1364- f"{ output_dir } /videos/traj_{ trajectory_name_text .value } .mp4" ,
1365- fps = framerate_number .value ,
1366- )
1367- max_frame = int (framerate_number .value * duration_number .value )
1368- assert max_frame > 0 and preview_frame_slider is not None
1369- preview_frame_slider .value = 0
1370- for _ in range (max_frame ):
1371- preview_frame_slider .value = (
1372- preview_frame_slider .value + 1
1373- ) % max_frame
1374- # should we use get_render here?
1375- image = client .camera .get_render (
1376- height = render_res_vec2 .value [1 ],
1377- width = render_res_vec2 .value [0 ],
1410+ if video_outfile .exists ():
1411+ with event .client .gui .add_modal ("Dump Video" ) as modal :
1412+ event .client .gui .add_markdown (
1413+ "Video already exists. Do you want to overwrite?"
13781414 )
1379- writer .append_data (image )
1380- writer .close ()
1381- print (f"Video saved to videos/traj_{ trajectory_name_text .value } .mp4" )
1382-
1383- dump_thread = threading .Thread (target = dump )
1384- dump_thread .start ()
1385- dump_thread .join ()
1386-
1387- # restore the original disabled state
1388- for handle , original_disabled in zip (handles_to_disable , original_disabled ):
1389- handle .disabled = original_disabled
1415+ overwrite_button = event .client .gui .add_button ("Overwrite" )
1416+ cancel_button = event .client .gui .add_button ("Cancel" )
13901417
1391- # exit preview render mode
1392- render_tab_state .preview_render = False
1418+ @overwrite_button .on_click
1419+ def _ (_ ) -> None :
1420+ modal .close ()
1421+ dump_video ()
13931422
1394- # Revert camera poses.
1395- with server .atomic ():
1396- for client in server .get_clients ().values ():
1397- if client .client_id not in camera_pose_backup_from_id :
1398- continue
1399- cam_position , cam_look_at , cam_up = camera_pose_backup_from_id .pop (
1400- client .client_id
1401- )
1402- client .camera .position = cam_position
1403- client .camera .look_at = cam_look_at
1404- client .camera .up_direction = cam_up
1405- client .flush ()
1423+ @cancel_button .on_click
1424+ def _ (_ ) -> None :
1425+ modal .close ()
14061426
1407- # Un-hide scene nodes.
1408- server . scene . set_global_visibility ( True )
1427+ else :
1428+ dump_video ( )
14091429
14101430 camera_path = CameraPath (server , duration_number )
14111431 camera_path .tension = tension_slider .value
0 commit comments