diff --git a/nerfstudio/viewer/export_panel.py b/nerfstudio/viewer/export_panel.py index a86586c45..c19c29b54 100644 --- a/nerfstudio/viewer/export_panel.py +++ b/nerfstudio/viewer/export_panel.py @@ -115,9 +115,9 @@ def populate_point_cloud_tab( hint="Normal map source.", ) - export_button = server.gui.add_button("Export", icon=viser.Icon.FILE_EXPORT) - download_button = server.gui.add_button("Download Point Cloud", icon=viser.Icon.DOWNLOAD) output_dir = server.gui.add_text("Output Directory", initial_value="exports/pcd/") + export_button = server.gui.add_button("Export", icon=viser.Icon.FILE_EXPORT) + download_button = server.gui.add_button("Download Point Cloud", icon=viser.Icon.DOWNLOAD, disabled=True) generate_command = server.gui.add_button("Generate Command", icon=viser.Icon.TERMINAL_2) @export_button.on_click @@ -129,6 +129,7 @@ def populate_point_cloud_tab( title="Exporting point cloud", body="File will be saved under " + str(output_dir.value), loading=True, + with_close_button=False, ) if control_panel.crop_obb is not None and control_panel.crop_viewport: @@ -154,10 +155,12 @@ def populate_point_cloud_tab( export.main() if export.complete: - notif.update( - title="Export complete!", - body="File saved under " + str(output_dir.value), - ) + notif.title = "Export complete!" + notif.body = "File saved under " + str(output_dir.value) + notif.loading = False + notif.with_close_button = True + + download_button.disabled = False @download_button.on_click def _(event: viser.GuiEvent) -> None: @@ -170,6 +173,23 @@ def populate_point_cloud_tab( client.send_file_download( "point_cloud.ply", ply_bytes ) + + @generate_command.on_click + def _(event: viser.GuiEvent) -> None: + assert event.client is not None + command = " ".join( + [ + "ns-export pointcloud", + f"--load-config {config_path}", + f"--output-dir {output_dir.value}", + f"--num-points {num_points.value}", + f"--remove-outliers {remove_outliers.value}", + f"--normal-method {normals.value}", + f"--save-world-frame {world_frame.value}", + get_crop_string(control_panel.crop_obb, control_panel.crop_viewport), + ] + ) + show_command_modal(event.client, "point cloud", command) else: server.gui.add_markdown("Point cloud export is not currently supported with Gaussian Splatting") @@ -194,12 +214,12 @@ def populate_mesh_tab( ) num_faces = server.gui.add_number("# Faces", initial_value=50_000, min=1) texture_resolution = server.gui.add_number("Texture Resolution", min=8, initial_value=2048) - output_dir = server.gui.add_text("Output Directory", initial_value="exports/mesh/") num_points = server.gui.add_number("# Points", initial_value=1_000_000, min=1, max=None, step=1) remove_outliers = server.gui.add_checkbox("Remove outliers", True) + output_dir = server.gui.add_text("Output Directory", initial_value="exports/mesh/") export_button = server.gui.add_button("Export", icon=viser.Icon.FILE_EXPORT) - download_button = server.gui.add_button("Download Mesh", icon=viser.Icon.DOWNLOAD) + download_button = server.gui.add_button("Download Mesh", icon=viser.Icon.DOWNLOAD, disabled=True) generate_command = server.gui.add_button("Generate Command", icon=viser.Icon.TERMINAL_2) @export_button.on_click @@ -211,6 +231,7 @@ def populate_mesh_tab( title="Exporting poisson mesh", body="File will be saved under " + str(output_dir.value), loading=True, + with_close_button=False, ) if control_panel.crop_obb is not None and control_panel.crop_viewport: @@ -237,10 +258,12 @@ def populate_mesh_tab( export.main() if export.complete: - notif.update( - title="Export complete!", - body="File saved under " + str(output_dir.value), - ) + notif.title = "Export complete!" + notif.body = "File saved under " + str(output_dir.value) + notif.loading = False + notif.with_close_button = True + + download_button.disabled = False @download_button.on_click def _(event: viser.GuiEvent) -> None: @@ -253,6 +276,24 @@ def populate_mesh_tab( client.send_file_download( "poisson_mesh.ply", ply_bytes ) + + @generate_command.on_click + def _(event: viser.GuiEvent) -> None: + assert event.client is not None + command = " ".join( + [ + "ns-export poisson", + f"--load-config {config_path}", + f"--output-dir {output_dir.value}", + f"--target-num-faces {num_faces.value}", + f"--num-pixels-per-side {texture_resolution.value}", + f"--num-points {num_points.value}", + f"--remove-outliers {remove_outliers.value}", + f"--normal-method {normals.value}", + get_crop_string(control_panel.crop_obb, control_panel.crop_viewport), + ] + ) + show_command_modal(event.client, "mesh", command) else: @@ -267,11 +308,9 @@ def populate_splat_tab( ) -> None: if viewing_gsplat: server.gui.add_markdown("Generate ply export of Gaussian Splat") - - export_button = server.gui.add_button("Export", icon=viser.Icon.FILE_EXPORT) - download_button = server.gui.add_button("Download Splat", icon=viser.Icon.DOWNLOAD) - output_dir = server.gui.add_text("Output Directory", initial_value="exports/splat/") + export_button = server.gui.add_button("Export", icon=viser.Icon.FILE_EXPORT) + download_button = server.gui.add_button("Download Splat", icon=viser.Icon.DOWNLOAD, disabled=True) generate_command = server.gui.add_button("Generate Command", icon=viser.Icon.TERMINAL_2) @export_button.on_click @@ -283,6 +322,7 @@ def populate_splat_tab( title="Exporting gaussian splat", body="File will be saved under " + str(output_dir.value), loading=True, + with_close_button=False, ) notif.show() @@ -305,10 +345,12 @@ def populate_splat_tab( export.main() if export.complete: - notif.update( - title="Export complete!", - body="File saved under " + str(output_dir.value), - ) + notif.title = "Export complete!" + notif.body = "File saved under " + str(output_dir.value) + notif.loading = False + notif.with_close_button = True + + download_button.disabled = False @download_button.on_click def _(event: viser.GuiEvent) -> None: @@ -321,6 +363,19 @@ def populate_splat_tab( client.send_file_download( "splat.ply", ply_bytes ) + + @generate_command.on_click + def _(event: viser.GuiEvent) -> None: + assert event.client is not None + command = " ".join( + [ + "ns-export gaussian-splat", + f"--load-config {config_path}", + f"--output-dir {output_directory.value}", + get_crop_string(control_panel.crop_obb, control_panel.crop_viewport), + ] + ) + show_command_modal(event.client, "splat", command) else: server.gui.add_markdown("Splat export is only supported with Gaussian Splatting methods")