From 121771d126a1c90cf39013d8016e16effbfe8efc Mon Sep 17 00:00:00 2001 From: Matthew Tancik Date: Wed, 2 Nov 2022 22:17:45 -0700 Subject: [PATCH] Update render UI (#885) * Update render UI * update text --- nerfstudio/viewer/app/src/index.scss | 65 +++++++++++++ .../src/modules/RenderModal/RenderModal.jsx | 93 +++++++++++++++++++ .../app/src/modules/RenderModal/index.jsx | 3 + .../SidePanel/CameraPanel/CameraPanel.jsx | 32 +++---- 4 files changed, 177 insertions(+), 16 deletions(-) create mode 100644 nerfstudio/viewer/app/src/modules/RenderModal/RenderModal.jsx create mode 100644 nerfstudio/viewer/app/src/modules/RenderModal/index.jsx diff --git a/nerfstudio/viewer/app/src/index.scss b/nerfstudio/viewer/app/src/index.scss index c39522b58..a27610a81 100644 --- a/nerfstudio/viewer/app/src/index.scss +++ b/nerfstudio/viewer/app/src/index.scss @@ -96,6 +96,29 @@ $sidebar-color: $accent-color3 !default; $sidebar-width: 100% !default; @import '~react-pro-sidebar/dist/scss/styles.scss'; +// Scrollbar + +/* width */ +::-webkit-scrollbar { + width: 8px; + height: 6px; +} + +/* Track */ +::-webkit-scrollbar-track { + background: #454651; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: $accent-color3; +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: $highlight-color2; +} + // ------------------------------------ // Status Panel styling .StatusPanel { @@ -161,6 +184,41 @@ $sidebar-width: 100% !default; margin: 3px; } +// ------------------------------------ +// Render Modal styling + +.RenderModal-box { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 600px; // 400 + background-color: $base-color2; + border: 2px solid #000; + // box-shadow: 24px 24px; + padding: 32px; +} + +.RenderModal-code { + padding: 10px; + background-color: $base-color3; + overflow-x: scroll; + font-family: monospace; + white-space: pre; + margin-top: 16px; +} + +.RenderModal-inline-code { + font-size: 0.9rem; + color: $accent-color3; +} + +.RenderModal-box .RenderModal-button { + width: 50%; + padding: 5px; + margin-top: 20px; +} + // ------------------------------------ // Camera Pane @@ -173,6 +231,13 @@ $sidebar-width: 100% !default; margin-top: 8px; } +.CameraPanel-render-button { + display: inline-block; + width: 70%; + margin: 4px; + margin-top: 8px; +} + .CameraPanel-slider-container { margin-top: 40px; margin-left: auto; diff --git a/nerfstudio/viewer/app/src/modules/RenderModal/RenderModal.jsx b/nerfstudio/viewer/app/src/modules/RenderModal/RenderModal.jsx new file mode 100644 index 000000000..6305d4043 --- /dev/null +++ b/nerfstudio/viewer/app/src/modules/RenderModal/RenderModal.jsx @@ -0,0 +1,93 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import * as React from 'react'; + +import { Box, Button, Modal, TextField, Typography } from '@mui/material'; +import { useSelector } from 'react-redux'; +import ContentCopyRoundedIcon from '@mui/icons-material/ContentCopyRounded'; + +interface RenderModalProps { + open: object; + setOpen: object; +} + +export default function RenderModal(props: RenderModalProps) { + const open = props.open; + const setOpen = props.setOpen; + + // redux store state + const config_base_dir = useSelector( + (state) => state.renderingState.config_base_dir, + ); + + // react state + const [filename, setFilename] = React.useState('render_output'); + + const handleClose = () => setOpen(false); + + // Copy the text inside the text field + const config_filename = `${config_base_dir}/config.yml`; + const camera_path_filename = `${config_base_dir}/camera_path.json`; + const cmd = `ns-render --load-config ${config_filename} --traj filename --camera-path-filename ${camera_path_filename} --output-path renders/${filename}.mp4`; + + const text_intro = `To render a full resolution video, run the following command in a terminal.`; + + const handleCopy = () => { + navigator.clipboard.writeText(cmd); + }; + + return ( +
+ + + +
+

Rendering

+

+ {text_intro} +
+ The video will be saved to{' '} + + ./renders/{filename}.mp4 + + . +

+ { + setFilename(e.target.value); + }} + value={filename} + variant="standard" + /> +
{cmd}
+
+ +
+
+
+
+
+
+ ); +} diff --git a/nerfstudio/viewer/app/src/modules/RenderModal/index.jsx b/nerfstudio/viewer/app/src/modules/RenderModal/index.jsx new file mode 100644 index 000000000..347dbeb7a --- /dev/null +++ b/nerfstudio/viewer/app/src/modules/RenderModal/index.jsx @@ -0,0 +1,3 @@ +import RenderModal from './RenderModal'; + +export default RenderModal; diff --git a/nerfstudio/viewer/app/src/modules/SidePanel/CameraPanel/CameraPanel.jsx b/nerfstudio/viewer/app/src/modules/SidePanel/CameraPanel/CameraPanel.jsx index 9f1cf207d..d55915ab0 100644 --- a/nerfstudio/viewer/app/src/modules/SidePanel/CameraPanel/CameraPanel.jsx +++ b/nerfstudio/viewer/app/src/modules/SidePanel/CameraPanel/CameraPanel.jsx @@ -19,12 +19,10 @@ import AddAPhotoIcon from '@mui/icons-material/AddAPhoto'; import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'; -import ContentPasteGoIcon from '@mui/icons-material/ContentPasteGo'; import DeleteIcon from '@mui/icons-material/Delete'; import FirstPageIcon from '@mui/icons-material/FirstPage'; import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined'; import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined'; -import IconButton from '@mui/material/IconButton'; import LastPageIcon from '@mui/icons-material/LastPage'; import PauseIcon from '@mui/icons-material/Pause'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; @@ -32,9 +30,11 @@ import { Stack } from '@mui/system'; import TextField from '@mui/material/TextField'; import Tooltip from '@mui/material/Tooltip'; import VisibilityIcon from '@mui/icons-material/Visibility'; +import VideoCameraBackIcon from '@mui/icons-material/VideoCameraBack'; import { CameraHelper } from './CameraHelper'; import { get_curve_object_from_cameras, get_transform_matrix } from './curve'; import { WebSocketContext } from '../../WebSocket/WebSocket'; +import RenderModal from '../../RenderModal'; const msgpack = require('msgpack-lite'); @@ -198,6 +198,7 @@ export default function CameraPanel(props) { const [is_linear, setIsLinear] = React.useState(false); const [seconds, setSeconds] = React.useState(4); const [fps, setFps] = React.useState(24); + const [render_modal_open, setRenderModalOpen] = React.useState(false); const dispatch = useDispatch(); const render_height = useSelector( @@ -529,16 +530,11 @@ export default function CameraPanel(props) { fr.readAsText(fileUpload); }; - const copy_cmd_to_clipboard = () => { - console.log('copy_cmd_to_clipboard'); + const open_render_modal = () => { + setRenderModalOpen(true); const camera_path_object = get_camera_path(); - - // Copy the text inside the text field - const config_filename = `${config_base_dir}/config.yml`; const camera_path_filename = `${config_base_dir}/camera_path.json`; - const cmd = `ns-render --load-config ${config_filename} --traj filename --camera-path-filename ${camera_path_filename} --output-path renders/output.mp4`; - navigator.clipboard.writeText(cmd); const camera_path_payload = { camera_path_filename, @@ -597,13 +593,17 @@ export default function CameraPanel(props) { Export Path -
- - - - - -
+
+ +