@@ -229,8 +229,6 @@ struct ControlEye {
229229 fov_y : Option < f32 > ,
230230
231231 did_interact : bool ,
232-
233- written_radius : bool ,
234232}
235233
236234impl ControlEye {
@@ -287,22 +285,13 @@ impl ControlEye {
287285 . 0 ,
288286 ) ;
289287
290- let has_look_target = eye_property
291- . component_or_empty :: < Position3D > ( EyeControls3D :: descriptor_look_target ( ) . component ) ?
292- . is_some ( ) ;
293-
294- let has_position = eye_property
295- . component_or_empty :: < Position3D > ( EyeControls3D :: descriptor_position ( ) . component ) ?
296- . is_some ( ) ;
297-
298288 Ok ( Self {
299289 pos,
300290 look_target,
301291 kind,
302292 speed,
303293 eye_up,
304294 did_interact : false ,
305- written_radius : has_position && has_look_target,
306295 fov_y,
307296 } )
308297 }
@@ -602,7 +591,7 @@ impl ControlEye {
602591 }
603592}
604593
605- fn find_camera ( space_cameras : & [ SpaceCamera3D ] , needle : & EntityPath ) -> Option < Eye > {
594+ pub fn find_camera ( space_cameras : & [ SpaceCamera3D ] , needle : & EntityPath ) -> Option < Eye > {
606595 let mut found_camera = None ;
607596
608597 for camera in space_cameras {
@@ -618,52 +607,6 @@ fn find_camera(space_cameras: &[SpaceCamera3D], needle: &EntityPath) -> Option<E
618607 found_camera. and_then ( Eye :: from_camera)
619608}
620609
621- /// Returns the new center and orbit radius for the eye.
622- fn entity_target_eye (
623- entity_path : & EntityPath ,
624- bounding_boxes : & SceneBoundingBoxes ,
625- eye : & mut ControlEye ,
626- ) {
627- // Note that we may want to focus on an _instance_ instead in the future:
628- // The problem with that is that there may be **many** instances (think point cloud)
629- // and they may not be consistent over time.
630- // -> we don't know the bounding box of every instance (right now)
631- // -> tracking instances over time may not be desired
632- // (this can happen with entities as well, but is less likely).
633- //
634- // For future reference, it's also worth pointing out that for interactions in the view we
635- // already have the 3D position:
636- // if let Some(SelectedSpaceContext::ThreeD {
637- // pos: Some(clicked_point),
638- // ..
639- // }) = ctx.selection_state().hovered_space_context()
640-
641- if let Some ( entity_bbox) = bounding_boxes. per_entity . get ( & entity_path. hash ( ) ) {
642- let radius = entity_bbox. centered_bounding_sphere_radius ( ) * 1.5 ;
643- let orbit_radius = if radius < 0.0001 {
644- // Handle zero-sized bounding boxes:
645- ( bounding_boxes. current . centered_bounding_sphere_radius ( ) * 1.5 ) . at_least ( 0.01 )
646- } else if eye. written_radius {
647- eye. pos . distance ( eye. look_target )
648- } else {
649- radius
650- } ;
651-
652- let fwd = eye. fwd ( ) ;
653-
654- match eye. kind {
655- Eye3DKind :: FirstPerson => {
656- eye. pos = entity_bbox. center ( ) ;
657- eye. look_target = entity_bbox. center ( ) + fwd;
658- }
659- Eye3DKind :: Orbital => {
660- eye. look_target = entity_bbox. center ( ) ;
661- eye. pos = entity_bbox. center ( ) - fwd * orbit_radius;
662- }
663- }
664- }
665- }
666-
667610fn ease_out ( t : f32 ) -> f32 {
668611 1. - ( 1. - t) * ( 1. - t)
669612}
@@ -681,6 +624,10 @@ impl EyeState {
681624 }
682625 }
683626
627+ fn stop_interpolation ( & mut self ) {
628+ self . interpolation = None ;
629+ }
630+
684631 /// Gets and updates the current target eye from/to the blueprint.
685632 fn control_and_sync_with_blueprint (
686633 & mut self ,
@@ -702,9 +649,17 @@ impl EyeState {
702649
703650 let mut drag_threshold = 0.0 ;
704651
705- let tracking_entity = eye_property. component_or_empty :: < re_types:: components:: EntityPath > (
706- EyeControls3D :: descriptor_tracking_entity ( ) . component ,
707- ) ?;
652+ let tracking_entity = eye_property
653+ . component_or_empty :: < re_types:: components:: EntityPath > (
654+ EyeControls3D :: descriptor_tracking_entity ( ) . component ,
655+ ) ?
656+ . and_then ( |tracking_entity| {
657+ if tracking_entity. is_empty ( ) {
658+ None
659+ } else {
660+ Some ( tracking_entity)
661+ }
662+ } ) ;
708663
709664 if let Some ( tracking_entity) = & tracking_entity {
710665 let tracking_entity = EntityPath :: from ( tracking_entity. as_str ( ) ) ;
@@ -717,6 +672,17 @@ impl EyeState {
717672 // to stop tracking.
718673 eye. handle_input ( self , response, drag_threshold) ;
719674
675+ eye. save_to_blueprint (
676+ ctx. viewer_ctx ,
677+ eye_property,
678+ old_pos,
679+ old_look_target,
680+ old_eye_up,
681+ ) ;
682+
683+ // Handle spinning after saving to blueprint to not continuously write to the blueprint.
684+ self . handle_spinning ( ctx, eye_property, & mut eye) ?;
685+
720686 if let Some ( tracked_eye) = self . handle_tracking_entity (
721687 ctx,
722688 eye_property,
@@ -730,17 +696,6 @@ impl EyeState {
730696 return Ok ( tracked_eye) ;
731697 }
732698
733- eye. save_to_blueprint (
734- ctx. viewer_ctx ,
735- eye_property,
736- old_pos,
737- old_look_target,
738- old_eye_up,
739- ) ;
740-
741- // Handle spinning after saving to blueprint to not continuously write to the blueprint.
742- self . handle_spinning ( ctx, eye_property, & mut eye) ?;
743-
744699 self . last_look_target = Some ( eye. look_target ) ;
745700 self . last_orbit_radius = Some ( eye. pos . distance ( eye. look_target ) ) ;
746701 self . last_eye_up = Some ( eye. up ( ) ) ;
@@ -764,10 +719,13 @@ impl EyeState {
764719 tracking_entity : Option < & re_types:: components:: EntityPath > ,
765720 ) -> Option < Eye > {
766721 if let Some ( tracking_entity) = & tracking_entity {
722+ // Don't do normal interpolation when tracking.
723+ self . stop_interpolation ( ) ;
767724 let tracking_entity = EntityPath :: from ( tracking_entity. as_str ( ) ) ;
768- if self . last_tracked_entity . as_ref ( ) == Some ( & tracking_entity) {
725+
726+ let new_tracking = self . last_tracked_entity . as_ref ( ) != Some ( & tracking_entity) ;
727+ if new_tracking {
769728 self . last_tracked_entity = Some ( tracking_entity. clone ( ) ) ;
770- self . start_interpolation ( ) ;
771729 }
772730
773731 let did_eye_change = match eye. kind {
@@ -790,8 +748,69 @@ impl EyeState {
790748 EyeControls3D :: descriptor_tracking_entity ( ) ,
791749 ) ;
792750 } else {
793- self . start_interpolation ( ) ;
794- entity_target_eye ( & tracking_entity, bounding_boxes, eye) ;
751+ // Note that we may want to focus on an _instance_ instead in the future:
752+ // The problem with that is that there may be **many** instances (think point cloud)
753+ // and they may not be consistent over time.
754+ // -> we don't know the bounding box of every instance (right now)
755+ // -> tracking instances over time may not be desired
756+ // (this can happen with entities as well, but is less likely).
757+ //
758+ // For future reference, it's also worth pointing out that for interactions in the view we
759+ // already have the 3D position:
760+ // if let Some(SelectedSpaceContext::ThreeD {
761+ // pos: Some(clicked_point),
762+ // ..
763+ // }) = ctx.selection_state().hovered_space_context()
764+
765+ if let Some ( entity_bbox) = bounding_boxes. per_entity . get ( & tracking_entity. hash ( ) ) {
766+ // If we're tracking something new, set the current position & look target to the correct view.
767+ if new_tracking {
768+ let fwd = eye. fwd ( ) ;
769+ let radius = entity_bbox. centered_bounding_sphere_radius ( ) * 1.5 ;
770+ let radius = if radius < 0.0001 {
771+ // Handle zero-sized bounding boxes:
772+ ( bounding_boxes. current . centered_bounding_sphere_radius ( ) * 1.5 )
773+ . at_least ( 0.02 )
774+ } else {
775+ radius
776+ } ;
777+ eye. pos = eye. look_target - fwd * radius;
778+ // Force write of pos and look target to not use fallbacks for that.
779+ eye_property. save_blueprint_component (
780+ ctx. viewer_ctx ,
781+ & EyeControls3D :: descriptor_position ( ) ,
782+ & Position3D :: from ( eye. pos ) ,
783+ ) ;
784+
785+ eye_property. save_blueprint_component (
786+ ctx. viewer_ctx ,
787+ & EyeControls3D :: descriptor_look_target ( ) ,
788+ & Position3D :: from ( eye. look_target ) ,
789+ ) ;
790+ }
791+
792+ let orbit_radius = eye. pos . distance ( eye. look_target ) ;
793+
794+ let pos = entity_bbox. center ( ) ;
795+
796+ let fwd = eye. fwd ( ) ;
797+
798+ match eye. kind {
799+ Eye3DKind :: FirstPerson => {
800+ eye. pos = pos;
801+ eye. look_target = pos + fwd;
802+ }
803+ Eye3DKind :: Orbital => {
804+ eye. look_target = pos;
805+ eye. pos = pos - fwd * orbit_radius;
806+ }
807+ }
808+ }
809+
810+ self . last_look_target = Some ( eye. look_target ) ;
811+ self . last_eye_up = Some ( eye. eye_up ) ;
812+ self . last_orbit_radius = Some ( eye. pos . distance ( eye. look_target ) ) ;
813+
795814 return Some ( eye. get_eye ( ) ) ;
796815 }
797816 } else {
@@ -841,6 +860,57 @@ impl EyeState {
841860 Ok ( ( ) )
842861 }
843862
863+ pub fn focus_entity (
864+ & self ,
865+ ctx : & ViewContext < ' _ > ,
866+ space_cameras : & [ SpaceCamera3D ] ,
867+ bounding_boxes : & SceneBoundingBoxes ,
868+ eye_property : & ViewProperty ,
869+ focused_entity : & EntityPath ,
870+ ) -> Result < ( ) , ViewPropertyQueryError > {
871+ let mut eye = ControlEye :: from_blueprint ( ctx, eye_property, self . fov_y ) ?;
872+ eye. did_interact = true ;
873+ let ControlEye {
874+ pos : old_pos,
875+ look_target : old_look_target,
876+ eye_up : old_eye_up,
877+ ..
878+ } = eye;
879+ // Focusing cameras is not something that happens now, since those are always tracked.
880+ if let Some ( target_eye) = find_camera ( space_cameras, focused_entity) {
881+ eye. pos = target_eye. pos_in_world ( ) ;
882+ eye. look_target = target_eye. pos_in_world ( ) + target_eye. forward_in_world ( ) ;
883+ eye. eye_up = target_eye. world_from_rub_view . transform_vector3 ( Vec3 :: Y ) ;
884+ } else if let Some ( entity_bbox) = bounding_boxes. per_entity . get ( & focused_entity. hash ( ) ) {
885+ let fwd = self
886+ . last_eye
887+ . map ( |eye| eye. forward_in_world ( ) )
888+ . unwrap_or_else ( || Vec3 :: splat ( f32:: sqrt ( 1.0 / 3.0 ) ) ) ;
889+ let radius = entity_bbox. centered_bounding_sphere_radius ( ) * 1.5 ;
890+ let radius = if radius < 0.0001 {
891+ // Handle zero-sized bounding boxes:
892+ ( bounding_boxes. current . centered_bounding_sphere_radius ( ) * 1.5 ) . at_least ( 0.02 )
893+ } else {
894+ radius
895+ } ;
896+ eye. look_target = entity_bbox. center ( ) ;
897+ eye. pos = eye. look_target - fwd * radius;
898+ }
899+
900+ eye. save_to_blueprint (
901+ ctx. viewer_ctx ,
902+ eye_property,
903+ old_pos,
904+ old_look_target,
905+ old_eye_up,
906+ ) ;
907+
908+ eye_property
909+ . clear_blueprint_component ( ctx. viewer_ctx , EyeControls3D :: descriptor_tracking_entity ( ) ) ;
910+
911+ Ok ( ( ) )
912+ }
913+
844914 pub fn update (
845915 & mut self ,
846916 ctx : & ViewContext < ' _ > ,
@@ -893,13 +963,10 @@ impl EyeState {
893963
894964 interpolation. start . lerp ( & target_eye, t)
895965 } else {
966+ self . stop_interpolation ( ) ;
896967 target_eye
897968 } ;
898969
899- if eye == target_eye {
900- self . interpolation = None ;
901- }
902-
903970 self . last_eye = Some ( eye) ;
904971
905972 Ok ( eye)
0 commit comments