Skip to content

Commit d5b68f2

Browse files
authored
Tracked 3D cameras lead now to on-hover rays in other space views that show the same camera but don't track it. (#1751)
In the same way as a 2D scene causes a on-hover ray in all space views that contain the space camera at which the 2D view "sits".
1 parent ef2b5dc commit d5b68f2

File tree

6 files changed

+112
-62
lines changed

6 files changed

+112
-62
lines changed

crates/re_viewer/src/misc/selection_state.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use egui::NumExt;
33
use lazy_static::lazy_static;
44
use nohash_hasher::IntMap;
55

6-
use re_data_store::{EntityPath, LogDb};
6+
use re_data_store::{EntityPath, InstancePath, InstancePathHash, LogDb};
77
use re_log_types::{component_types::InstanceKey, EntityPathHash};
88
use re_renderer::OutlineMaskPreference;
99

@@ -29,8 +29,15 @@ pub enum HoveredSpace {
2929
/// The 3D space with the camera(s)
3030
space_3d: EntityPath,
3131

32-
/// 2D spaces and pixel coordinates (with Z=depth)
33-
target_spaces: Vec<(EntityPath, Option<glam::Vec3>)>,
32+
/// The point in 3D space that is hovered, if any.
33+
pos: Option<glam::Vec3>,
34+
35+
/// Path of a space camera, this 3D space is viewed through.
36+
/// (None for a free floating Eye)
37+
tracked_space_camera: Option<InstancePath>,
38+
39+
/// Corresponding 2D spaces and pixel coordinates (with Z=depth)
40+
point_in_space_cameras: Vec<(InstancePathHash, Option<glam::Vec3>)>,
3441
},
3542
}
3643

crates/re_viewer/src/ui/view_spatial/scene/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl SceneSpatial {
232232
if self
233233
.space_cameras
234234
.iter()
235-
.any(|camera| &camera.entity_path != space_info_path)
235+
.any(|camera| camera.instance_path_hash.entity_path_hash != space_info_path.hash())
236236
{
237237
return SpatialNavigationMode::ThreeD;
238238
}

crates/re_viewer/src/ui/view_spatial/scene/scene_part/cameras.rs

-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ impl CamerasPart {
8989
let frustum_length = *props.pinhole_image_plane_distance.get();
9090

9191
scene.space_cameras.push(SpaceCamera3D {
92-
entity_path: entity_path.clone(),
9392
instance_path_hash,
9493
view_coordinates,
9594
world_from_camera,

crates/re_viewer/src/ui/view_spatial/space_camera_3d.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
use glam::{vec3, Affine3A, Mat3, Quat, Vec2, Vec3};
22
use macaw::{IsoTransform, Ray3};
33

4-
use re_data_store::{EntityPath, InstancePathHash};
4+
use re_data_store::InstancePathHash;
55
use re_log_types::ViewCoordinates;
66

77
/// A logged camera that connects spaces.
88
#[derive(Clone)]
99
pub struct SpaceCamera3D {
10-
/// Path to the entity which has the projection (pinhole, ortho or otherwise) transforms.
10+
/// Path to the instance which has the projection (pinhole, ortho or otherwise) transforms.
1111
///
12-
/// We expect the camera transform to apply to this entity and every path below it.
13-
pub entity_path: EntityPath,
14-
15-
/// The instance that has the projection.
12+
/// We expect the camera transform to apply to this instance and every path below it.
1613
pub instance_path_hash: InstancePathHash,
1714

1815
/// The coordinate system of the camera ("view-space").
@@ -49,7 +46,7 @@ impl SpaceCamera3D {
4946
match from_rub_quat(self.view_coordinates) {
5047
Ok(from_rub) => Some(self.world_from_camera * IsoTransform::from_quat(from_rub)),
5148
Err(err) => {
52-
re_log::warn_once!("Camera {:?}: {err}", self.entity_path);
49+
re_log::warn_once!("Camera {:?}: {err}", self.instance_path_hash);
5350
None
5451
}
5552
}

crates/re_viewer/src/ui/view_spatial/ui_2d.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -581,9 +581,13 @@ fn show_projections_from_3d_space(
581581
ui_from_space: &RectTransform,
582582
) -> Vec<Shape> {
583583
let mut shapes = Vec::new();
584-
if let HoveredSpace::ThreeD { target_spaces, .. } = ctx.selection_state().hovered_space() {
584+
if let HoveredSpace::ThreeD {
585+
point_in_space_cameras: target_spaces,
586+
..
587+
} = ctx.selection_state().hovered_space()
588+
{
585589
for (space_2d, pos_2d) in target_spaces {
586-
if space_2d == space {
590+
if space_2d.entity_path_hash == space.hash() {
587591
if let Some(pos_2d) = pos_2d {
588592
// User is hovering a 2D point inside a 3D view.
589593
let pos_in_ui = ui_from_space.transform_pos(pos2(pos_2d.x, pos_2d.y));

crates/re_viewer/src/ui/view_spatial/ui_3d.rs

+91-48
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::{
2929

3030
use super::{
3131
eye::{Eye, OrbitEye},
32+
scene::SceneSpatialPrimitives,
3233
ViewSpatialState,
3334
};
3435

@@ -454,13 +455,29 @@ pub fn view_3d(
454455
.resolve(&ctx.log_db.entity_db)
455456
.map(|instance_path| Item::InstancePath(Some(space_view_id), instance_path))
456457
}));
457-
state.state_3d.hovered_point = picking_result
458+
459+
let hovered_point = picking_result
458460
.opaque_hit
459461
.as_ref()
460462
.or_else(|| picking_result.transparent_hits.last())
461463
.map(|hit| picking_result.space_position(hit));
462464

463-
project_onto_other_spaces(ctx, &scene.space_cameras, &mut state.state_3d, space);
465+
ctx.selection_state_mut()
466+
.set_hovered_space(HoveredSpace::ThreeD {
467+
space_3d: space.clone(),
468+
pos: hovered_point,
469+
tracked_space_camera: state.state_3d.tracked_camera.clone(),
470+
point_in_space_cameras: scene
471+
.space_cameras
472+
.iter()
473+
.map(|cam| {
474+
(
475+
cam.instance_path_hash,
476+
hovered_point.and_then(|pos| cam.project_onto_2d(pos)),
477+
)
478+
})
479+
.collect(),
480+
});
464481
} else {
465482
state.previous_picking_result = None;
466483
}
@@ -516,7 +533,12 @@ pub fn view_3d(
516533
view_builder.schedule_screenshot(ctx.render_ctx, space_view_id.gpu_readback_id(), mode);
517534
}
518535

519-
show_projections_from_2d_space(ctx, &mut scene, &state.scene_bbox_accum);
536+
show_projections_from_2d_space(
537+
ctx,
538+
&mut scene,
539+
&state.state_3d.tracked_camera,
540+
&state.scene_bbox_accum,
541+
);
520542

521543
if state.state_3d.show_axes {
522544
let axis_length = 1.0; // The axes are also a measuring stick
@@ -591,13 +613,16 @@ pub fn view_3d(
591613
fn show_projections_from_2d_space(
592614
ctx: &mut ViewerContext<'_>,
593615
scene: &mut SceneSpatial,
616+
tracked_space_camera: &Option<InstancePath>,
594617
scene_bbox_accum: &BoundingBox,
595618
) {
596-
if let HoveredSpace::TwoD { space_2d, pos } = ctx.selection_state().hovered_space() {
597-
let mut line_batch = scene.primitives.line_strips.batch("picking ray");
598-
599-
for cam in &scene.space_cameras {
600-
if &cam.entity_path == space_2d {
619+
match ctx.selection_state().hovered_space() {
620+
HoveredSpace::TwoD { space_2d, pos } => {
621+
if let Some(cam) = scene
622+
.space_cameras
623+
.iter()
624+
.find(|cam| cam.instance_path_hash.entity_path_hash == space_2d.hash())
625+
{
601626
if let Some(ray) = cam.unproject_as_ray(glam::vec2(pos.x, pos.y)) {
602627
// Render a thick line to the actual z value if any and a weaker one as an extension
603628
// If we don't have a z value, we only render the thick one.
@@ -607,54 +632,72 @@ fn show_projections_from_2d_space(
607632
cam.picture_plane_distance
608633
};
609634

610-
let origin = ray.point_along(0.0);
611-
// No harm in making this ray _very_ long. (Infinite messes with things though!)
612-
let fallback_ray_end = ray.point_along(scene_bbox_accum.size().length() * 10.0);
613-
614-
if let Some(line_length) = thick_ray_length {
615-
let main_ray_end = ray.point_along(line_length);
616-
line_batch
617-
.add_segment(origin, main_ray_end)
618-
.color(egui::Color32::WHITE)
619-
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
620-
.radius(Size::new_points(1.0));
621-
line_batch
622-
.add_segment(main_ray_end, fallback_ray_end)
623-
.color(egui::Color32::DARK_GRAY)
624-
// TODO(andreas): Make this dashed.
625-
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
626-
.radius(Size::new_points(0.5));
627-
} else {
628-
line_batch
629-
.add_segment(origin, fallback_ray_end)
630-
.color(egui::Color32::WHITE)
631-
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
632-
.radius(Size::new_points(1.0));
633-
}
635+
add_picking_ray(
636+
&mut scene.primitives,
637+
ray,
638+
scene_bbox_accum,
639+
thick_ray_length,
640+
);
634641
}
635642
}
636643
}
644+
HoveredSpace::ThreeD {
645+
pos: Some(pos),
646+
tracked_space_camera: Some(camera_path),
647+
..
648+
} => {
649+
if tracked_space_camera
650+
.as_ref()
651+
.map_or(true, |tracked| tracked != camera_path)
652+
{
653+
if let Some(cam) = scene
654+
.space_cameras
655+
.iter()
656+
.find(|cam| cam.instance_path_hash == camera_path.hash())
657+
{
658+
let cam_to_pos = *pos - cam.position();
659+
let distance = cam_to_pos.length();
660+
let ray = macaw::Ray3::from_origin_dir(cam.position(), cam_to_pos / distance);
661+
add_picking_ray(&mut scene.primitives, ray, scene_bbox_accum, Some(distance));
662+
}
663+
}
664+
}
665+
_ => {}
637666
}
638667
}
639668

640-
fn project_onto_other_spaces(
641-
ctx: &mut ViewerContext<'_>,
642-
space_cameras: &[SpaceCamera3D],
643-
state: &mut View3DState,
644-
space: &EntityPath,
669+
fn add_picking_ray(
670+
primitives: &mut SceneSpatialPrimitives,
671+
ray: macaw::Ray3,
672+
scene_bbox_accum: &BoundingBox,
673+
thick_ray_length: Option<f32>,
645674
) {
646-
let mut target_spaces = vec![];
647-
for cam in space_cameras {
648-
let point_in_2d = state
649-
.hovered_point
650-
.and_then(|hovered_point| cam.project_onto_2d(hovered_point));
651-
target_spaces.push((cam.entity_path.clone(), point_in_2d));
675+
let mut line_batch = primitives.line_strips.batch("picking ray");
676+
677+
let origin = ray.point_along(0.0);
678+
// No harm in making this ray _very_ long. (Infinite messes with things though!)
679+
let fallback_ray_end = ray.point_along(scene_bbox_accum.size().length() * 10.0);
680+
681+
if let Some(line_length) = thick_ray_length {
682+
let main_ray_end = ray.point_along(line_length);
683+
line_batch
684+
.add_segment(origin, main_ray_end)
685+
.color(egui::Color32::WHITE)
686+
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
687+
.radius(Size::new_points(1.0));
688+
line_batch
689+
.add_segment(main_ray_end, fallback_ray_end)
690+
.color(egui::Color32::DARK_GRAY)
691+
// TODO(andreas): Make this dashed.
692+
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
693+
.radius(Size::new_points(0.5));
694+
} else {
695+
line_batch
696+
.add_segment(origin, fallback_ray_end)
697+
.color(egui::Color32::WHITE)
698+
.flags(re_renderer::renderer::LineStripFlags::NO_COLOR_GRADIENT)
699+
.radius(Size::new_points(1.0));
652700
}
653-
ctx.selection_state_mut()
654-
.set_hovered_space(HoveredSpace::ThreeD {
655-
space_3d: space.clone(),
656-
target_spaces,
657-
});
658701
}
659702

660703
fn default_eye(scene_bbox: &macaw::BoundingBox, space_specs: &SpaceSpecs) -> OrbitEye {

0 commit comments

Comments
 (0)