4
0
mirror of https://github.com/nerfstudio-project/nerfstudio.git synced 2026-11-11 02:24:38 +08:00

Catch-all for some front-end viewer bugs (#503)

* (1) remove green camera helper when no cameras (2) remove remaining spline if no more cameras

* removed transform stuff if camera is deleted

* rm transform controls when deleted; only show render helper when 2 cameras present; disable play if max of slider reached

* fixed weird glitching; made render camera snap immediately to moved camera

* click off will remove transform

* lint
This commit is contained in:
evonneng 2022-09-22 21:49:26 -07:00 committed by GitHub
parent 1c0ede17a9
commit 1d8e1eabc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 128 additions and 22 deletions

View File

@ -65,6 +65,22 @@ export default class SceneNode {
return this.find(path.concat(['<object>'])).object;
}
find_no_create(path) {
if (path.length === 0) {
return this;
}
const name = path[0];
const child = this.children[name];
if (child === undefined) {
return null;
}
return child.find(path.slice(1));
}
find_object_no_create(path){
return this.find_no_create(path.concat(['<object>'])).object;
}
set_property(property, value) {
if (property === 'position') {
this.object.position.set(value[0], value[1], value[2]);

View File

@ -26,7 +26,6 @@ import { WebSocketContext } from '../../WebSocket/WebSocket';
const msgpack = require('msgpack-lite');
function set_camera_position(camera, matrix) {
// console.log("setting camera position");
const mat = new THREE.Matrix4();
mat.fromArray(matrix.elements);
mat.decompose(camera.position, camera.quaternion, camera.scale);
@ -38,25 +37,83 @@ function CameraList(props) {
const camera_main = props.camera_main;
const transform_controls = props.transform_controls;
const setCameras = props.setCameras;
// eslint-disable-next-line no-unused-vars
const [slider_value, set_slider_value] = React.useState(0);
const set_transform_controls = (index) => {
// camera helper object so grab the camera inside
const camera = sceneTree.find_object([
const camera = sceneTree.find_object_no_create([
'Camera Path',
'Cameras',
index.toString(),
'Camera',
]);
transform_controls.attach(camera);
if (camera !== null) {
const viewer_buttons = document.getElementsByClassName(
'ViewerWindow-buttons',
)[0];
if (camera === transform_controls.object){
transform_controls.detach();
viewer_buttons.style.display = 'none';
} else{
transform_controls.detach();
transform_controls.attach(camera);
viewer_buttons.style.display = 'block';
}
}
};
const reset_slider_render_on_delete = () => {
// set slider and render camera back to 0
const slider_min = 0;
const camera_render = sceneTree.find_object_no_create(['Cameras', 'Render Camera']);
const camera_render_helper = sceneTree.find_object_no_create([
'Cameras',
'Render Camera',
'Helper',
]);
if (cameras.length >= 1) {
let first_camera = sceneTree.find_object_no_create([
'Camera Path',
'Cameras',
0,
'Camera',
]);
if (first_camera.type !== "PerspectiveCamera" && cameras.length > 1) {
first_camera = sceneTree.find_object_no_create([
'Camera Path',
'Cameras',
1,
'Camera',
]);
}
set_camera_position(camera_render, first_camera.matrix);
camera_render_helper.set_visibility(true);
set_slider_value(slider_min);
}
}
const delete_camera = (index) => {
const camera_render_helper = sceneTree.find_object_no_create([
'Cameras',
'Render Camera',
'Helper',
]);
console.log('TODO: deleting camera: ', index);
sceneTree.delete(['Camera Path', 'Cameras', index.toString(), 'Camera']);
sceneTree.delete(['Camera Path', 'Cameras', index.toString(), 'Camera Helper']);
setCameras([...cameras.slice(0, index), ...cameras.slice(index + 1)]);
// detach and hide transform controls
transform_controls.detach();
const viewer_buttons = document.getElementsByClassName(
'ViewerWindow-buttons',
)[0];
viewer_buttons.style.display = 'block';
};
const delete_camera = (index) => {
console.log('TODO: deleting camera: ', index);
setCameras([...cameras.slice(0, index), ...cameras.slice(index + 1)]);
viewer_buttons.style.display = 'none';
if (cameras.length < 1) {
camera_render_helper.set_visibility(false);
}
reset_slider_render_on_delete();
};
const cameraList = cameras.map((camera, index) => {
@ -84,14 +141,14 @@ function CameraList(props) {
export default function CameraPanel(props) {
// unpack relevant information
const sceneTree = props.sceneTree;
const camera_main = sceneTree.find_object(['Cameras', 'Main Camera']);
const camera_render = sceneTree.find_object(['Cameras', 'Render Camera']);
const camera_render_helper = sceneTree.find_object([
const camera_main = sceneTree.find_object_no_create(['Cameras', 'Main Camera']);
const camera_render = sceneTree.find_object_no_create(['Cameras', 'Render Camera']);
const camera_render_helper = sceneTree.find_object_no_create([
'Cameras',
'Render Camera',
'Helper',
]);
const transform_controls = sceneTree.find_object(['Transform Controls']);
const transform_controls = sceneTree.find_object_no_create(['Transform Controls']);
// redux store state
const config_base_dir = useSelector(
@ -145,13 +202,20 @@ export default function CameraPanel(props) {
const slider_min = 0;
const slider_max = Math.max(0, cameras.length - 1);
const reset_slider_render_on_add = (new_camera_list) => {
// set slider and render camera back to 0
if (new_camera_list.length >= 1){
set_camera_position(camera_render, new_camera_list[0].matrix);
set_slider_value(slider_min);
}
}
const add_camera = () => {
const camera_main_copy = camera_main.clone();
camera_main_copy.aspect = 1.0;
const new_camera_list = cameras.concat(camera_main_copy);
setCameras(new_camera_list);
set_camera_position(camera_render, camera_main_copy.matrix);
camera_render_helper.set_visibility(true);
reset_slider_render_on_add(new_camera_list);
};
// force a rerender if the cameras are dragged around
@ -161,9 +225,7 @@ export default function CameraPanel(props) {
// prevent multiple loops
if (update_cameras_interval === null) {
// hardcoded for 100 ms per udpate
update_cameras_interval = setInterval(() => {
setCameras(cameras);
}, 100);
update_cameras_interval = setInterval(() => {}, 100);
}
});
// eslint-disable-next-line no-unused-vars
@ -171,6 +233,7 @@ export default function CameraPanel(props) {
if (update_cameras_interval !== null) {
clearInterval(update_cameras_interval);
update_cameras_interval = null;
setCameras(cameras);
}
});
@ -184,6 +247,11 @@ export default function CameraPanel(props) {
});
sceneTree.delete(['Camera Path', 'Cameras']); // delete old cameras, which is important
if (cameras.length < 1) {
camera_render_helper.set_visibility(false);
} else {
camera_render_helper.set_visibility(true);
}
for (let i = 0; i < cameras.length; i += 1) {
const camera = cameras[i];
// camera.aspect = render_width / render_height;
@ -213,6 +281,7 @@ export default function CameraPanel(props) {
// update the camera curve
const curve_object = get_curve_object_from_cameras(cameras);
if (cameras.length > 1) {
const num_points = fps * seconds;
const points = curve_object.curve_positions.getPoints(num_points);
@ -222,6 +291,21 @@ export default function CameraPanel(props) {
const material = new MeshLineMaterial({ lineWidth: 0.01, color: 0xff5024 });
const spline_mesh = new THREE.Mesh(spline.geometry, material);
sceneTree.set_object_from_path(['Camera Path', 'Curve'], spline_mesh);
// set the camera
const position = curve_object.curve_positions.getPoint(
slider_value / (cameras.length - 1.0),
);
const lookat = curve_object.curve_lookats.getPoint(
slider_value / (cameras.length - 1.0),
);
const up = curve_object.curve_ups.getPoint(
slider_value / (cameras.length - 1.0),
);
const mat = get_transform_matrix(position, lookat, up);
set_camera_position(camera_render, mat);
} else {
sceneTree.delete(['Camera Path', 'Curve']);
}
const marks = [];
@ -249,7 +333,7 @@ export default function CameraPanel(props) {
// call this function whenever slider state changes
useEffect(() => {
if (is_playing) {
if (is_playing && cameras.length > 1) {
const interval = setInterval(() => {
set_slider_value((prev) => prev + step_size);
}, 1000 / fps);
@ -422,7 +506,9 @@ export default function CameraPanel(props) {
<Button
variant="outlined"
onClick={() => {
setIsPlaying(true);
if(cameras.length > 1){
setIsPlaying(true);
}
}}
>
<PlayArrowIcon />

View File

@ -49,7 +49,6 @@ export function get_curve_object_from_cameras(cameras) {
curve_lookats,
curve_ups,
};
return curve_object;
}

View File

@ -156,7 +156,12 @@ function MenuItems(props: ListItemProps) {
{terminal ? null : (
<Collapse in={open} timeout="auto">
<List>
{Object.keys(scene_node.children).map((key) => (
{Object.keys(scene_node.children).filter( (key) => {
if (key === "Camera") {
return false; // skip
}
return true;
}).map((key) => (
<MenuItems
name={key}
scene_node={scene_node.children[key]}