From 00338d024457e769c30e269176e8a1feac2a716f Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Thu, 29 Jun 2023 16:07:06 -0300 Subject: [PATCH 1/9] MRH3-62 Eye Tracking Examples Feedback - Add documentation for the basic example scene scripts - Add documentation for the target selection scene scripts - Add documentation for the eye gaze visualizer scene scripts - Add missing component menus to eye tracking scene scripts - Update variable naming to lower camel case - Some refactoring of the eye gaze visualizer log classes --- .../EyeTrackingExample-05-Visualizer.unity | 16 +++++ .../Assets/Scripts/EyeTracking/ColorTap.cs | 28 +++++++- .../Scripts/EyeTracking/FollowEyeGaze.cs | 3 + .../EyeTracking/KeywordRecognitionHandler.cs | 4 ++ .../ScrollPanZoom/OnLookAtRotateByEyeGaze.cs | 15 ++-- .../TargetPositioning/MoveObjectByEyeGaze.cs | 71 +++++++++++-------- .../TargetPositioning/ObjectGoalZone.cs | 2 - .../TransportToRespawnLocation.cs | 2 - .../TargetSelectionDemo/EyeTrackingTarget.cs | 2 +- .../TargetSelectionDemo/FaceUser.cs | 1 + .../TargetGroupCreatorRadial.cs | 2 - .../Visualizer/BasicInputLogger.cs | 2 +- .../EyeTracking/Visualizer/DrawOnTexture.cs | 24 +++++-- .../EyeTracking/Visualizer/LogStructure.cs | 12 +++- .../Visualizer/LogStructureEyeGaze.cs | 19 +++-- .../Visualizer/UserInputPlayback.cs | 12 ++-- .../Visualizer/UserInputRecorder.cs | 18 ++--- .../Visualizer/tex_heatramp.png.meta | 8 +-- 18 files changed, 166 insertions(+), 75 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity index f0010cebe14..625123f8642 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity @@ -1854,6 +1854,14 @@ PrefabInstance: propertyPath: m_InteractionManager value: objectReference: {fileID: 525252188} + - target: {fileID: 1524931721158149771, guid: 7fee940c81bcd264699d55f5dacdcf88, type: 3} + propertyPath: minThreshDeltaHeatMap + value: 0.0001 + objectReference: {fileID: 0} + - target: {fileID: 1524931721158149771, guid: 7fee940c81bcd264699d55f5dacdcf88, type: 3} + propertyPath: minThresholdDeltaHeatMap + value: 0.001 + objectReference: {fileID: 0} - target: {fileID: 3200108193205774659, guid: 7fee940c81bcd264699d55f5dacdcf88, type: 3} propertyPath: m_Name value: LiveTrackingSample @@ -1926,6 +1934,14 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 870610049} m_Modifications: + - target: {fileID: 4863657714435241520, guid: 64e53d8562025f543b10498ba7cdaa3e, type: 3} + propertyPath: minThreshDeltaHeatMap + value: 0.0001 + objectReference: {fileID: 0} + - target: {fileID: 4863657714435241520, guid: 64e53d8562025f543b10498ba7cdaa3e, type: 3} + propertyPath: minThresholdDeltaHeatMap + value: 0.001 + objectReference: {fileID: 0} - target: {fileID: 8729132920210686062, guid: 64e53d8562025f543b10498ba7cdaa3e, type: 3} propertyPath: m_RootOrder value: 1 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ColorTap.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ColorTap.cs index d7ffa268168..0d4d5061147 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ColorTap.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ColorTap.cs @@ -5,18 +5,25 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - using UnityEngine.Serialization; using UnityEngine.XR.Interaction.Toolkit; + /// + /// Example of how to attach functions to StatefulInteractables. + /// + /// [RequireComponent(typeof(Renderer))] + [AddComponentMenu("Scripts/MRTK/Examples/ColorTap")] public class ColorTap : MonoBehaviour { + [Tooltip("The default color of the GameObject.")] [SerializeField] private Color idleStateColor = Color.cyan; + [Tooltip("The hovered color of the GameObject.")] [SerializeField] private Color onHoverColor = Color.white; + [Tooltip("The selected color of the GameObject.")] [SerializeField] private Color onSelectColor = Color.blue; @@ -27,31 +34,50 @@ private void Awake() material = GetComponent().material; } + /// + /// Triggered when the attached enters eye gaze. + /// public void OnGazeHoverEntered() { material.color = onHoverColor; } + /// + /// Triggered when the attached leaves eye gaze. + /// public void OnGazeHoverExited() { material.color = idleStateColor; } + /// + /// Triggered when the attached starts a gaze pinch gesture. + /// public void OnGazePinchEntered() { material.color = onHoverColor; } + /// + /// Triggered when the attached ends a gaze pinch gesture. + /// public void OnGazePinchExited() { material.color = idleStateColor; } + /// + /// Triggered when the attached is selected. + /// public void OnSelectEntered(SelectEnterEventArgs _) { material.color = onSelectColor; } + /// + /// Triggered when the attached is de-selected. + /// + /// public void OnSelectExited(SelectExitEventArgs _) { material.color = onHoverColor; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs index 187bbe77628..f6587078248 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs @@ -14,15 +14,18 @@ namespace Microsoft.MixedReality.Toolkit.Examples /// Sample for allowing the game object that this script is attached to follow the user's eye gaze /// at a given distance of "DefaultDistanceInMeters". /// + [AddComponentMenu("Scripts/MRTK/Examples/FollowEyeGaze")] public class FollowEyeGaze : MonoBehaviour { [Tooltip("Display the game object along the eye gaze ray at a default distance (in meters).")] [SerializeField] private float _defaultDistanceInMeters = 2f; + [Tooltip("The default color of the GameObject.")] [SerializeField] private Color _idleStateColor; + [Tooltip("The highlight color of the GameObject when hovered over another StatefulInteractable.")] [SerializeField] private Color _hightlightStateColor; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/KeywordRecognitionHandler.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/KeywordRecognitionHandler.cs index 63bac0867cb..cbf2d9c2c37 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/KeywordRecognitionHandler.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/KeywordRecognitionHandler.cs @@ -9,6 +9,9 @@ namespace Microsoft.MixedReality.Toolkit.Examples { + /// + /// Sample for binding speech recognition keywords to Unity Event functions. + /// public class KeywordRecognitionHandler : MonoBehaviour { [Serializable] @@ -21,6 +24,7 @@ public struct KeywordEvent public UnityEvent Event; } + [Tooltip("List of speech recognition keywords and events to trigger.")] [SerializeField] private List _keywords = new List(); diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/OnLookAtRotateByEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/OnLookAtRotateByEyeGaze.cs index ddc1ee801ce..361c022296f 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/OnLookAtRotateByEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/OnLookAtRotateByEyeGaze.cs @@ -52,6 +52,9 @@ public class OnLookAtRotateByEyeGaze : StatefulInteractable private float maxRotationY = 180.0f; #endregion + /// + /// Updates the rotation of the GameObject based on the current eye gaze position. + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { // Dynamic is effectively just your normal Update(). @@ -61,15 +64,15 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up { if (interactor is FuzzyGazeInteractor gaze) { - Vector3 TargetToHit = (gameObject.transform.position - gaze.PreciseHitResult.raycastHit.point).normalized; - Vector3 TargetToCamera = (gameObject.transform.position - Camera.main.transform.position).normalized; + Vector3 targetToHit = (gameObject.transform.position - gaze.PreciseHitResult.raycastHit.point).normalized; + Vector3 targetToCamera = (gameObject.transform.position - Camera.main.transform.position).normalized; - float angle1x = Mathf.Atan2(TargetToHit.y, TargetToHit.z); - float angle1y = Mathf.Atan2(TargetToHit.x * Mathf.Cos(angle1x), TargetToHit.z); + float angle1x = Mathf.Atan2(targetToHit.y, targetToHit.z); + float angle1y = Mathf.Atan2(targetToHit.x * Mathf.Cos(angle1x), targetToHit.z); float angle1z = Mathf.Atan2(Mathf.Cos(angle1x), Mathf.Sin(angle1x) * Mathf.Sin(angle1y)); - float angle2x = Mathf.Atan2(TargetToCamera.y, TargetToCamera.z); - float angle2y = Mathf.Atan2(TargetToCamera.x * Mathf.Cos(angle2x), TargetToCamera.z); + float angle2x = Mathf.Atan2(targetToCamera.y, targetToCamera.z); + float angle2y = Mathf.Atan2(targetToCamera.x * Mathf.Cos(angle2x), targetToCamera.z); if (angle1y > 0f && angle1z < 0f) { diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs index 23f0bad8987..63ca2c01353 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs @@ -8,11 +8,13 @@ namespace Microsoft.MixedReality.Toolkit.Examples { using Input; using Subsystems; - using UnityEngine.Serialization; using UnityEngine.XR; using UnityEngine.XR.Interaction.Toolkit; - public enum PlacementSurfaces + /// + /// Specifies the allowed surface orientations to place GameObjects with attached on. + /// + internal enum PlacementSurfaces { Horizontal, Vertical @@ -25,12 +27,14 @@ public enum PlacementSurfaces [AddComponentMenu("Scripts/MRTK/Examples/MoveObjectByEyeGaze")] public class MoveObjectByEyeGaze : StatefulInteractable { + [Tooltip("Reference to the FuzzyGazeInteractor in the scene")] [SerializeField] private FuzzyGazeInteractor gazeInteractor; #region Serialized variables [Header("Eyes")] + [Tooltip("Use this to toggle eye gaze interactions.")] [SerializeField] private bool useEyeSupportedTargetPlacement = false; @@ -41,7 +45,7 @@ public class MoveObjectByEyeGaze : StatefulInteractable private float minLookAwayDistToEnableEyeWarp = 5f; [Header("Hands")] - [Tooltip("Use this to enforce only voice commands to move targets.")] + [Tooltip("Use this to toggle hand based interactions.")] [SerializeField] private bool handInputEnabled = true; @@ -73,28 +77,43 @@ public class MoveObjectByEyeGaze : StatefulInteractable private float previewPlacementDistanceThreshold = 0.05f; [Header("Constrained Movement")] + [Tooltip("Freeze the X position of the GameObject.")] [SerializeField] private bool freezeX = false; + [Tooltip("Freeze the Y position of the GameObject.")] [SerializeField] private bool freezeY = false; + [Tooltip("Freeze the Z position of the GameObject.")] [SerializeField] private bool freezeZ = false; + [Tooltip("Specifies whether the GameObject moves on horizontal or vertical surfaces.")] + [SerializeField] + private PlacementSurfaces placementSurface = PlacementSurfaces.Horizontal; + + /// + /// Limits the X position of the GameObject to the specified minimum and maximum. + /// public Vector2 LocalMinMaxX = new Vector2(float.NegativeInfinity, float.PositiveInfinity); - public Vector2 LocalMinMaxY = new Vector2(float.NegativeInfinity, float.PositiveInfinity); - public Vector2 LocalMinMaxZ = new Vector2(float.NegativeInfinity, float.PositiveInfinity); - public PlacementSurfaces PlacementSurface = PlacementSurfaces.Horizontal; + /// + /// Limits the Y position of the GameObject to the specified minimum and maximum. + /// + public Vector2 LocalMinMaxY = new Vector2(float.NegativeInfinity, float.PositiveInfinity); + /// + /// Limits the Z position of the GameObject to the specified minimum and maximum. + /// + public Vector2 LocalMinMaxZ = new Vector2(float.NegativeInfinity, float.PositiveInfinity); + + [Tooltip("Fired when the GameObject is dropped.")] [SerializeField] private UnityEvent onDrop = null; - #endregion #region Private variables - private GameObject previewGameObject; private bool @@ -124,14 +143,13 @@ private bool private Ray? headPreviousRay; private float headDeltaDirectionThreshold = 0.05f; private float headSmoothf = 0.1f; - private bool headIsInMotion; private float headDeltaDirectionf = 0f; private int ConstraintX => freezeX ? 0 : 1; private int ConstraintY => freezeY ? 0 : 1; private int ConstraintZ => freezeZ ? 0 : 1; - Vector3? _prevPreviewPos; + Vector3? previousPreviewPosition; // The values represent the maximum angle that the surface can be offset from the 'up' vector to be considered for horizontal placement. // For example, if a surface is slanted by 40 degrees targets may slid off and hence we may consider this an invalid offset angle. @@ -225,7 +243,7 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up } else { - if (PlacementSurface == PlacementSurfaces.Horizontal) + if (placementSurface == PlacementSurfaces.Horizontal) { previewGameObject.transform.position = plausibleLocation.Value + previewGameObject.transform.localScale.y * Vector3.up / @@ -237,7 +255,7 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up plausibleLocation.Value; } - _prevPreviewPos = previewGameObject.transform.position; + previousPreviewPosition = previewGameObject.transform.position; } } else @@ -253,7 +271,7 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up } else { - _prevPreviewPos = null; + previousPreviewPosition = null; } } } @@ -338,15 +356,15 @@ private bool IsLookingAwayFromTarget() /// private bool IsLookingAwayFromPreview() { - if (_prevPreviewPos == null) + if (previousPreviewPosition == null) { return true; } - Vector3 eyes2PrevPreview = _prevPreviewPos.Value - Camera.main.transform.position; - Vector3 eye2HitPos = Camera.main.transform.forward; + Vector3 eyes2PreviousPreview = previousPreviewPosition.Value - Camera.main.transform.position; + Vector3 eye2HitPosition = Camera.main.transform.forward; - float distance = EyeTrackingUtilities.VisAngleInDegreesToMeters(Vector3.Angle(eyes2PrevPreview, eye2HitPos), eye2HitPos.magnitude); + float distance = EyeTrackingUtilities.VisAngleInDegreesToMeters(Vector3.Angle(eyes2PreviousPreview, eye2HitPosition), eye2HitPosition.magnitude); if (distance < previewPlacementDistanceThreshold) { @@ -361,11 +379,8 @@ private bool IsLookingAwayFromPreview() // Check whether the user is still looking within the proximity of the target float distanceBetweenTargetAndCurrHitPos = Angle_ToCurrHitTarget(previewGameObject); - if (distanceBetweenTargetAndCurrHitPos > minLookAwayDistToEnableEyeWarp) - { - return true; - } - return false; + + return distanceBetweenTargetAndCurrHitPos > minLookAwayDistToEnableEyeWarp; } /// @@ -375,7 +390,7 @@ private bool IsLookingAwayFromPreview() /// True if the target can be placed on this surface. private bool IsDestinationPlausible() { - if (PlacementSurface == PlacementSurfaces.Horizontal) + if (placementSurface == PlacementSurfaces.Horizontal) { float angle = Vector3.Angle(gazeInteractor.PreciseHitResult.raycastHit.normal, Vector3.up); if (angle < maxDiffAngleForHorizontalPlacement) // If the angle is more than for example 20 degrees off from the up vector @@ -384,7 +399,7 @@ private bool IsDestinationPlausible() } } - else if (PlacementSurface == PlacementSurfaces.Vertical) + else if (placementSurface == PlacementSurfaces.Vertical) { float angle = Vector3.Angle(gazeInteractor.PreciseHitResult.raycastHit.normal, gameObject.transform.up); if (angle > minDiffAngleForVerticalPlacement) @@ -533,6 +548,8 @@ public float Angle_ToCurrHitTarget(GameObject gobj) private bool HeadIsInMotion() { + bool headIsInMotion = false; + Vector3 pos = Camera.main.transform.position; Vector3 forward = Camera.main.transform.forward; @@ -547,8 +564,6 @@ private bool HeadIsInMotion() headIsInMotion = headDeltaDirectionf > headDeltaDirectionThreshold; } } - else - headIsInMotion = false; headPreviousRay = new Ray(pos, forward); // Update recent head move @@ -577,7 +592,7 @@ public void MoveTargetBy(Vector3 delta) Vector3 hitPosition = gazeInteractor.PreciseHitResult.raycastHit.point; // Discrete cursor-based target movement - if (PlacementSurface == PlacementSurfaces.Horizontal) + if (placementSurface == PlacementSurfaces.Horizontal) { hitPosition.y += gameObject.transform.localScale.y * 0.5f; } @@ -648,7 +663,7 @@ public void MoveTargetTo(Vector3 destination) if (ShouldObjBeWarped(deltaHand, Angle_ToCurrHitTarget(gameObject), headIsInMotion)) { // Discrete cursor-based target movement - if (PlacementSurface == PlacementSurfaces.Horizontal) + if (placementSurface == PlacementSurfaces.Horizontal) { destination.y += gameObject.transform.localScale.y * 0.5f; } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs index a8bd4537aab..07b1d201bf4 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs @@ -6,8 +6,6 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - using UnityEngine.Serialization; - /// /// This associated GameObject acts a target goal zone to place other GameObjects inside. /// diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/TransportToRespawnLocation.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/TransportToRespawnLocation.cs index 919c0f5406f..303f54b256c 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/TransportToRespawnLocation.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/TransportToRespawnLocation.cs @@ -5,8 +5,6 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - using UnityEngine.Serialization; - /// /// The associated GameObject acts as a teleporter to a referenced respawn location when /// a GameObject enters the attached collider volume. diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs index 19397798d1d..a174433f72b 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs @@ -6,11 +6,11 @@ namespace Microsoft.MixedReality.Toolkit.Examples { using System.Collections; - using UnityEngine.Serialization; /// /// Handles events triggered from the attached /// + [AddComponentMenu("Scripts/MRTK/Examples/EyeTrackingTarget")] public class EyeTrackingTarget : MonoBehaviour { [Tooltip("Visual effect (e.g., particle explosion or animation) that is played when a target is selected.")] diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs index 7431a525a5e..fabcb069824 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs @@ -12,6 +12,7 @@ namespace Microsoft.MixedReality.Toolkit.Examples /// eye gaze: The currently looked at part will move towards the /// front, facing the user. /// + [AddComponentMenu("Scripts/MRTK/Examples/FaceUser")] public class FaceUser : MonoBehaviour { #region Serialized variables diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs index 668f7e05c7a..b6773011629 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs @@ -6,8 +6,6 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - using UnityEngine.Serialization; - /// /// Handles the creation of a group of targets based on a list of given templates. /// diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs index 8f50d3cdfe5..983643f201e 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs @@ -45,7 +45,7 @@ public void SetSessionDescription(string description) internal bool IsLogging = false; protected abstract string GetFileName(); - private StringBuilder buffer = null; + private StringBuilder buffer; #if WINDOWS_UWP protected virtual async void CreateNewLogFile() diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/DrawOnTexture.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/DrawOnTexture.cs index 67a64e85630..e0b4e8679e5 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/DrawOnTexture.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/DrawOnTexture.cs @@ -16,18 +16,23 @@ namespace Microsoft.MixedReality.Toolkit.Examples [RequireComponent(typeof(Renderer))] internal class DrawOnTexture : MRTKBaseInteractable { + [Tooltip("A lookup texture that ramps from [0,1] in UV co-ordinates in attention values")] [SerializeField] private Texture2D heatmapLookUpTable; + [Tooltip("The brush size or spread from the eye gaze point")] [SerializeField] - private float drawBrushSize = 2000.0f; // aka spread + private float drawBrushSize = 2000.0f; + [Tooltip("The intensity or amplitude of the brush that falls off from the eye gaze point")] [SerializeField] - private float drawIntensity = 15.0f; // aka amplitude + private float drawIntensity = 15.0f; + [Tooltip("The minimum threshold value to apply colors to the heat map")] [SerializeField] - private float minThreshDeltaHeatMap = 0.001f; // Mostly for performance to reduce spreading heatmap for small values. + private float minThresholdDeltaHeatMap = 0.001f; // Mostly for performance to reduce spreading heatmap for small values. + [Tooltip("Toggle to update the heat map in real-time or use recorded values")] [SerializeField] private bool useLiveInputStream = false; @@ -66,8 +71,13 @@ protected override void OnDestroy() base.OnDestroy(); } + /// + /// Updates the heat map with the current eye gaze position. + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) - { + { + base.ProcessInteractable(updatePhase); + // Dynamic is effectively just your normal Update(). if (updatePhase == XRInteractionUpdateOrder.UpdatePhase.Dynamic && useLiveInputStream) { @@ -82,6 +92,10 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up } } + /// + /// Updates the heat map with a hit at . + /// + /// The hit position in world co-ordinates. public void DrawAtThisHitPos(Vector3 hitPosition) { Vector2? hitPosUV = GetCursorPosInTexture(hitPosition); @@ -158,7 +172,7 @@ private bool ComputeHeatmapColorAt(Vector2 currentPoint, Vector2 originalPivot, float B = 2f; float scaledInterest = 1f / (1f + Mathf.Pow(Mathf.Epsilon, -(B * distCenterToCurrPnt))); float delta = scaledInterest / amplitude; - if (delta < minThreshDeltaHeatMap) + if (delta < minThresholdDeltaHeatMap) return false; Color baseColor = texture.GetPixel((int)currentPoint.x, (int)currentPoint.y); diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructure.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructure.cs index 93447cd4ccc..773b854042c 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructure.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructure.cs @@ -6,15 +6,23 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - [AddComponentMenu("Scripts/MRTK/Examples/LogStructure")] + /// + /// Abstract base class for defining file or stream logging structure types. + /// public abstract class LogStructure : MonoBehaviour { + /// + /// Returns the headers of the log structure. + /// public virtual string[] GetHeaderColumns() { return Array.Empty(); } - public virtual object[] GetData(string inputType, string inputStatus, EyeTrackingTarget intTarget) + /// + /// Returns a row of logging data. + /// + public virtual object[] GetData() { return Array.Empty(); } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs index 499ebcf4a20..b89dec3c9dc 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs @@ -7,12 +7,18 @@ namespace Microsoft.MixedReality.Toolkit.Examples { using Input; + /// + /// A CSV file logging structure for eye gaze data. + /// [AddComponentMenu("Scripts/MRTK/Examples/LogStructureEyeGaze")] public class LogStructureEyeGaze : LogStructure { [SerializeField] private FuzzyGazeInteractor gazeInteractor; + /// + /// The headers of the eye gaze file structure. + /// public override string[] GetHeaderColumns() { return new string[] @@ -43,12 +49,15 @@ public override string[] GetHeaderColumns() }; } - public override object[] GetData(string inputType, string inputStatus, EyeTrackingTarget intTarget) + /// + /// Returns the eye gaze data captured during an update frame. + /// + public override object[] GetData() { // Let's prepare all the data we wanna log // Eye gaze hit position - Vector3? eyeHitPos = gazeInteractor.PreciseHitResult.raycastHit.point; + Vector3 eyeHitPos = gazeInteractor.PreciseHitResult.raycastHit.point; object[] data = new object[] { @@ -69,9 +78,9 @@ public override object[] GetData(string inputType, string inputStatus, EyeTracki gazeInteractor.rayOriginTransform.forward.y, gazeInteractor.rayOriginTransform.forward.z, - eyeHitPos.HasValue ? eyeHitPos.Value.x : float.NaN, - eyeHitPos.HasValue ? eyeHitPos.Value.y : float.NaN, - eyeHitPos.HasValue ? eyeHitPos.Value.z : float.NaN + eyeHitPos.x, + eyeHitPos.y, + eyeHitPos.z }; return data; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs index 6ca3b4ad10c..11bf6d9ab74 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs @@ -132,7 +132,7 @@ public void LoadNewFile(string filename) loggedLines.Add(line); } LoadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; - Log(("Finished loading log file. Lines: " + loggedLines.Count)); + Log("Finished loading log file. Lines: " + loggedLines.Count); } catch (Exception e) { @@ -301,6 +301,10 @@ private void ShowHeatmap() private void LoadingStatus_Hide() { + if (LoadingUpdateStatusText != null) + { + LoadingUpdateStatusText.gameObject.SetActive(true); + } } private void LoadingStatus_Show() @@ -368,12 +372,12 @@ private IEnumerator UpdateStatus(float updateFrequency) LoadingStatus_Hide(); } - private Ray? GetEyeRay(IReadOnlyList split) + private static Ray? GetEyeRay(IReadOnlyList split) { return GetRay(split[9], split[10], split[11], split[12], split[13], split[14]); } - private Ray? GetRay(string originX, string originY, string originZ, string dirX, string dirY, string dirZ) + private static Ray? GetRay(string originX, string originY, string originZ, string dirX, string dirY, string dirZ) { bool isValidVec1 = TryParseStringToVector3(originX, originY, originZ, out Vector3 origin); bool isValidVec2 = TryParseStringToVector3(dirX, dirY, dirZ, out Vector3 dir); @@ -406,7 +410,7 @@ private void UpdateTimestampForNextReplay(IReadOnlyList split) } } - private void UpdateEyeGazeSignal(IReadOnlyListsplit, InputPointerVisualizer visualizer) + private static void UpdateEyeGazeSignal(IReadOnlyListsplit, InputPointerVisualizer visualizer) { Ray? ray = GetEyeRay(split); if (ray.HasValue) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs index 6e5c9cc71e4..400ff8dedb9 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs @@ -41,15 +41,14 @@ public override string GetHeader() string headerFormat = GetStringFormat(headerColumns); return string.Format(headerFormat, headerColumns); } - else - return ""; + + return ""; } // Todo: Put into BasicLogger? protected object[] GetData_Part1() { - object[] data = new object[] - { + object[] data = { // UserId UserName, // SessionType @@ -86,24 +85,19 @@ public static string GetStringFormat(object[] data) return strFormat.ToString(); } - public void UpdateLog(string inputType, string inputStatus, EyeTrackingTarget intendedTarget) + public void UpdateLog() { if (Instance != null && IsLogging) { if (logStructure != null) { - object[] data = MergeObjArrays(GetData_Part1(), logStructure.GetData(inputType, inputStatus, intendedTarget)); + object[] data = MergeObjArrays(GetData_Part1(), logStructure.GetData()); string data_format = GetStringFormat(data); - Instance.CustomAppend(String.Format(data_format, data)); + Instance.CustomAppend(string.Format(data_format, data)); } } } - public void UpdateLog() - { - UpdateLog("", "", null); - } - private void Update() { if (automaticLogging) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Textures/EyeTrackingExamples/Visualizer/tex_heatramp.png.meta b/UnityProjects/MRTKDevTemplate/Assets/Textures/EyeTrackingExamples/Visualizer/tex_heatramp.png.meta index 153c33984e3..1691c7909c9 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Textures/EyeTrackingExamples/Visualizer/tex_heatramp.png.meta +++ b/UnityProjects/MRTKDevTemplate/Assets/Textures/EyeTrackingExamples/Visualizer/tex_heatramp.png.meta @@ -6,7 +6,7 @@ TextureImporter: serializedVersion: 12 mipmaps: mipMapMode: 0 - enableMipMap: 1 + enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -36,9 +36,9 @@ TextureImporter: filterMode: 1 aniso: 1 mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 nPOTScale: 1 lightmap: 0 compressionQuality: 50 From 811bb3b67f7e6048f77f477acba970441902c700 Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Tue, 4 Jul 2023 11:11:08 -0300 Subject: [PATCH 2/9] MRH3-62 Eye Tracking Examples Feedback - Add documentation for the eye based navigation sample --- .../EyeGazeRotation (1).prefab | 2 +- .../EyeTrackingExample-03-Navigation.unity | 46 +++++++++++++------ .../ScrollPanZoom/TargetMoveToCamera.cs | 19 ++++++-- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/NavigationExample/EyeGazeRotation (1).prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/NavigationExample/EyeGazeRotation (1).prefab index d0e8dbd3dcc..fdce18367ef 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/NavigationExample/EyeGazeRotation (1).prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/NavigationExample/EyeGazeRotation (1).prefab @@ -392,7 +392,7 @@ MonoBehaviour: handType: 3 proximityType: 3 executionOrder: 1 - minimumScale: {x: 0.2, y: 0.2, z: 0.2} + minimumScale: {x: 0.5, y: 0.5, z: 0.5} maximumScale: {x: 2, y: 2, z: 2} relativeToInitialState: 1 --- !u!114 &1808124033441462826 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-03-Navigation.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-03-Navigation.unity index 5934a3e6c9e..ba322d0d632 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-03-Navigation.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-03-Navigation.unity @@ -2990,6 +2990,38 @@ PrefabInstance: propertyPath: isGazePinchSelected.onEntered.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName value: UnityEngine.Object, UnityEngine objectReference: {fileID: 0} + - target: {fileID: 348134655595542138, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontAsset + value: + objectReference: {fileID: 11400000, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontStyle + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontColor.b + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontColor.g + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontColor.r + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_sharedMaterial + value: + objectReference: {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + - target: {fileID: 348134655595542139, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} + propertyPath: m_fontColor32.rgba + value: 4294967295 + objectReference: {fileID: 0} - target: {fileID: 2789646968690223496, guid: d341ff791a3249540a0c38121c47a9b9, type: 3} propertyPath: m_Name value: PanAndZoomExample @@ -3092,18 +3124,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 1156823076} m_Modifications: - - target: {fileID: 1808124033441462824, guid: 9715efe25e795694e9e2df61c9d8c6bb, type: 3} - propertyPath: minimumScale.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 1808124033441462824, guid: 9715efe25e795694e9e2df61c9d8c6bb, type: 3} - propertyPath: minimumScale.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 1808124033441462824, guid: 9715efe25e795694e9e2df61c9d8c6bb, type: 3} - propertyPath: minimumScale.z - value: 0.5 - objectReference: {fileID: 0} - target: {fileID: 1808124033441462828, guid: 9715efe25e795694e9e2df61c9d8c6bb, type: 3} propertyPath: m_InteractionManager value: @@ -3335,7 +3355,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2362020300155552838, guid: 223005b231c33c5449426df912d4de39, type: 3} propertyPath: m_AnchoredPosition.y - value: -512.9503 + value: -512.9508 objectReference: {fileID: 0} - target: {fileID: 2362020300408418987, guid: 223005b231c33c5449426df912d4de39, type: 3} propertyPath: m_Name diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/TargetMoveToCamera.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/TargetMoveToCamera.cs index f029ab60a74..9fea223d6fe 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/TargetMoveToCamera.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/TargetMoveToCamera.cs @@ -13,16 +13,21 @@ namespace Microsoft.MixedReality.Toolkit.Examples [AddComponentMenu("Scripts/MRTK/Examples/TargetMoveToCamera")] public class TargetMoveToCamera : OnLookAtRotateByEyeGaze { - public static TargetMoveToCamera currentlyFocusedTarget; + private static TargetMoveToCamera currentlyFocusedTarget; - public float DistanceToCamera = 6f; + [Tooltip("The focus distance of the GameObject in front of the camera when it is selected")] + [SerializeField] + private float DistanceToCamera = 1f; + [Tooltip("Speed of the object when transitioning when selected or deselected")] [SerializeField] private float speed = 1f; + [Tooltip("The distance threshold to stop transitioning when selected")] [SerializeField] private float minDistanceToStopTransition = 1f; + [Tooltip("Toggles the GameObject to rotate by eye gaze when selected")] [SerializeField] private bool setToAutoRotateIfFocused = true; @@ -35,6 +40,9 @@ private void Start() originalPosition = transform.position; } + /// + /// Transitions the GameObject to the camera and the original world position when selected or deselected. + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { // Dynamic is effectively just your normal Update(). @@ -49,6 +57,9 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up } } + /// + /// Fired when the GameObject is selected or deselected. + /// public void OnSelect() { if (isInNearFocusMode) @@ -61,7 +72,7 @@ public void OnSelect() } } - public void TransitionToUser() + private void TransitionToUser() { SpeechRecognitionKeyword = "send back"; @@ -78,7 +89,7 @@ public void TransitionToUser() inTransition = true; } - public void ReturnHome() + private void ReturnHome() { SpeechRecognitionKeyword = "come to me"; From 12f5fb8bb0019606c77c62117187fe95fc54617a Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Tue, 4 Jul 2023 13:56:00 -0300 Subject: [PATCH 3/9] MRH3-62 Eye Tracking Examples Feedback - Refactoring the visualizer sample scene - Removed InputPointerVisualizer which was unused in the sample - Removed InputPointerVisualer code from UserInputPlayback - Moved the inheritance base file logging functionality of UserInputRecorder into FileInputLogger --- .../EyeTrackingExample-05-Visualizer.unity | 97 ++++-- .../Visualizer/CustomInputLogger.cs | 55 ---- .../Visualizer/CustomInputLogger.cs.meta | 11 - ...BasicInputLogger.cs => FileInputLogger.cs} | 153 ++++------ ...Logger.cs.meta => FileInputLogger.cs.meta} | 2 +- .../Visualizer/UserInputPlayback.cs | 278 ++++-------------- .../Visualizer/UserInputRecorder.cs | 129 ++++---- 7 files changed, 242 insertions(+), 483 deletions(-) delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs.meta rename UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/{BasicInputLogger.cs => FileInputLogger.cs} (59%) rename UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/{BasicInputLogger.cs.meta => FileInputLogger.cs.meta} (83%) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity index 625123f8642..3e959a19ed1 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity @@ -1107,7 +1107,6 @@ GameObject: m_Component: - component: {fileID: 1232406735} - component: {fileID: 1232406737} - - component: {fileID: 1232406736} m_Layer: 0 m_Name: ET_Visualizer m_TagString: Untagged @@ -1130,30 +1129,6 @@ Transform: m_Father: {fileID: 870610049} m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1232406736 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1232406734} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d181de5344315d24b8bce19d973451c7, type: 3} - m_Name: - m_EditorClassIdentifier: - useLiveInputStream: 0 - ShowVisMode: 0 - onlyShowForHitTargets: 0 - templateOrigins: {fileID: 0} - templateDestinations: {fileID: 0} - templateLinkOrigToOrig: {fileID: 0} - templateLinkDestToDest: {fileID: 0} - templateLinkOrigToDest: {fileID: 0} - cursorDist: 2 - gazeInteractor: {fileID: 0} - numSamples: 20 - textOutput: {fileID: 0} --- !u!114 &1232406737 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1166,14 +1141,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: dc6f7049651e8bc4eb6ce6985ebd3777, type: 3} m_Name: m_EditorClassIdentifier: - customFilename: mrtk_log_mostRecentET.csv - EyeGazeVisualizer: {fileID: 1232406736} - HeadGazeVisualizer: {fileID: 0} + playbackLogFilename: mrtk_log_mostRecentET.csv heatmapReferences: - {fileID: 1018849797} - {fileID: 1524931721350790071} - LoadingUpdateStatusText: {fileID: 947746751} - NumSamples: 30 + loadingUpdateStatusText: {fileID: 947746751} replaySpeed: 1 --- !u!224 &1261404671 stripped RectTransform: @@ -1999,6 +1971,26 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 870610049} m_Modifications: + - target: {fileID: 2087141182152323438, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: m_Enabled + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName + value: set_enabled + objectReference: {fileID: 0} + - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName + value: UnityEngine.Behaviour, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_BoolArgument + value: 1 + objectReference: {fileID: 0} - target: {fileID: 5853303421825090637, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: m_RootOrder value: 2 @@ -2047,9 +2039,25 @@ PrefabInstance: propertyPath: m_Name value: Controls objectReference: {fileID: 0} + - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName + value: set_enabled + objectReference: {fileID: 0} + - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName + value: UnityEngine.Behaviour, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_BoolArgument + value: 0 + objectReference: {fileID: 0} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.size - value: 4 + value: 1 objectReference: {fileID: 0} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode @@ -2059,6 +2067,14 @@ PrefabInstance: propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_Mode value: 1 objectReference: {fileID: 0} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 1232406737} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target + value: + objectReference: {fileID: 1232406737} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Target value: @@ -2076,13 +2092,30 @@ PrefabInstance: value: 2 objectReference: {fileID: 0} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: StartPlayback + objectReference: {fileID: 0} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName value: ShowAllAndFreeze objectReference: {fileID: 0} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName + value: Play + objectReference: {fileID: 0} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_MethodName value: Play objectReference: {fileID: 0} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputPlayback, Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputPlayback, + Assembly-CSharp + objectReference: {fileID: 0} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputPlayback, diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs deleted file mode 100644 index a1d54ed6ef1..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using UnityEngine; - -namespace Microsoft.MixedReality.Toolkit.Examples -{ - public abstract class CustomInputLogger : BasicInputLogger - { - [Tooltip("The data will be saved as CSV files.")] - protected string filename = null; - - protected static DateTime TimerStart; - - protected bool PrintedHeader = false; - - protected virtual void CustomAppend(string msg) - { - // Check if we've logged the header yet - if (!PrintedHeader) - PrintedHeader = Append(GetHeader()); - - // Log the actual message - Append(msg); - } - - protected void CreateNewLog() - { - Debug.Log(">> CreateNewLog "); - ResetLog(); - TimerStart = DateTime.UtcNow; // Reset timer - PrintedHeader = false; // Set false, so that a new header is printed - } - - public void StartLogging() - { - Debug.Log(">> START LOGGING! "); - CreateNewLog(); - IsLogging = true; - } - - public void StopLoggingAndSave() - { - Debug.Log(">> STOP LOGGING and save! "); - SaveLogs(); - IsLogging = false; - } - - public void CancelLogging() - { - IsLogging = false; - } - } -} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs.meta deleted file mode 100644 index e34eeef2f46..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/CustomInputLogger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8f5c73b580bd9aa41a21654712a03435 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs similarity index 59% rename from UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs rename to UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs index 983643f201e..1586d4283cc 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; @@ -12,42 +12,59 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - public abstract class BasicInputLogger : MonoBehaviour + /// + /// + /// + public class FileInputLogger : IDisposable { - public bool AddTimestampToLogfileName = false; - - public void SetUserName(string name) + private bool disposed = false; + private StreamWriter logFile = null; + private string userName; + + public FileInputLogger(string userName, string fileName) { - UserName = name; - Debug.Log("New user name: " + name); - } + UserName = userName; - public void SetSessionDescription(string description) - { - sessionDescription = description; - Debug.Log("New session name: " + description); +#if WINDOWS_UWP + await CreateNewLogFile(); +#else + logFile = File.CreateText(Application.persistentDataPath + "/" + fileName); + logFile.AutoFlush = true; +#endif } - public string UserName = "tester"; + /// + /// Closes the log file and releases any managed resources. + /// + public void Dispose() + { + if (disposed) + { + return; + } - [SerializeField] - protected string sessionDescription = "Session00"; + disposed = true; - public string LogDirectory => "MRTK_ET_Demo/" + UserName; + logFile.Close(); + logFile.Dispose(); + } - public abstract string GetHeader(); + /// + /// + /// + public string UserName + { + get { return userName; } + set { userName = value; } + } #if WINDOWS_UWP + public string LogDirectory => "MRTK_ET_Demo/" + UserName; + private StorageFile logFile; private StorageFolder logRootFolder = KnownFolders.MusicLibrary; private StorageFolder sessionFolder; -#endif - internal bool IsLogging = false; - protected abstract string GetFileName(); - private StringBuilder buffer; - -#if WINDOWS_UWP protected virtual async void CreateNewLogFile() { try @@ -87,43 +104,21 @@ protected virtual async void CreateNewLogFile() } } #endif - - void CheckIfInitialized() - { - if (buffer == null) - ResetLog(); - } - - public void ResetLog() - { - buffer = new StringBuilder(); + +#region Append Log #if WINDOWS_UWP - CreateNewLogFile(); -#endif - } - - private static string FormattedTimeStamp + public async void AppendLog(string message) { - get - { - return DateTime.Now.ToString("yMMddHHmmss"); - } + // Log buffer to the file + await FileIO.AppendTextAsync(logFile, message); } - - #region Append log - public bool Append(string msg) +#else + public void AppendLog(string message) { - CheckIfInitialized(); - - if (IsLogging) - { - // post IO to a separate thread. - buffer.AppendLine(msg); - return true; - } - return false; + logFile.Write(message); } - #endregion +#endif +#endregion #if WINDOWS_UWP public async void LoadLogs() @@ -143,8 +138,6 @@ public async void LoadLogs() sessionFolder = await logRootFolder.GetFolderAsync(LogDirectory); logFile = await sessionFolder.GetFileAsync(filename); - - } catch (FileNotFoundException) { @@ -160,51 +153,5 @@ public async void LoadLogs() } } #endif - -#if WINDOWS_UWP - public async void SaveLogs() - { - if (IsLogging) - { - if (buffer.Length > 0) - { - // Log buffer to the file - await FileIO.AppendTextAsync(logFile, buffer.ToString()); - } - } - } -#else - public void SaveLogs() - { - if (IsLogging) - { - string path = Application.persistentDataPath + "/" + Filename; - - Debug.Log("SAVE LOGS to " + path); - File.WriteAllText(path, buffer.ToString()); - } - } -#endif - - private string Filename - { - get { return AddTimestampToLogfileName ? FilenameWithTimestamp : FilenameNoTimestamp; } - } - - protected string FilenameWithTimestamp - { - get { return $"{FormattedTimeStamp}_{FilenameNoTimestamp}"; } - } - - protected string FilenameNoTimestamp - { - get { return GetFileName() + ".csv"; } - } - - public virtual void OnDestroy() - { - if (IsLogging) - SaveLogs(); - } } } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs.meta similarity index 83% rename from UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs.meta rename to UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs.meta index 64b4f011f04..9e0f26a9946 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/BasicInputLogger.cs.meta +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 11e61eb554001914585df39669c1a499 +guid: 465d3cded64971e4f8a3a1eeee531859 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs index 11bf6d9ab74..861449d1275 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs @@ -19,15 +19,15 @@ namespace Microsoft.MixedReality.Toolkit.Examples public class UserInputPlayback : MonoBehaviour { [SerializeField] - private string customFilename = string.Empty; - - public InputPointerVisualizer EyeGazeVisualizer; - public InputPointerVisualizer HeadGazeVisualizer; + private string playbackLogFilename = string.Empty; [SerializeField] private DrawOnTexture[] heatmapReferences = null; - private List loggedLines; + [SerializeField] + private TextMeshPro loadingUpdateStatusText; + + private IReadOnlyList loggedLines; #if WINDOWS_UWP private StorageFolder uwpRootFolder = KnownFolders.MusicLibrary; @@ -40,13 +40,12 @@ public class UserInputPlayback : MonoBehaviour private void Start() { IsPlaying = false; - ResetCurrentStream(); LoadingStatus_Hide(); } private void ResetCurrentStream() { - loggedLines = new List(); + loggedLines = null; } #if WINDOWS_UWP @@ -62,12 +61,12 @@ public async Task UWP_LoadNewFile(string filename) if (fileExists) { - LoadingUpdateStatusText.text = "File exists: " + uwpFileName; + loadingUpdateStatusText.text = "File exists: " + uwpFileName; await UWP_ReadData(uwpLogFile); } else { - LoadingUpdateStatusText.text = "Error: File does not exist! " + uwpFileName; + loadingUpdateStatusText.text = "Error: File does not exist! " + uwpFileName; return false; } @@ -85,7 +84,7 @@ public async Task UWP_FileExists(string dir, string filename) } catch { - LoadingUpdateStatusText.text = "Error: File could not be found."; + loadingUpdateStatusText.text = "Error: File could not be found."; } return false; @@ -100,12 +99,17 @@ private async Task UWP_ReadData(StorageFile logfile) { loggedLines.Add(streamReader.ReadLine()); } - LoadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; + loadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; return true; } #endif - public void LoadNewFile(string filename) + private bool DataIsLoaded + { + get { return loggedLines != null && loggedLines.Count > 0; } + } + + private void LoadNewFile(string filename) { ResetCurrentStream(); @@ -117,7 +121,7 @@ public void LoadNewFile(string filename) if (!File.Exists(filename)) #endif { - LoadingUpdateStatusText.text += "Error: Playback log file does not exist! ->> " + filename + " <<"; + loadingUpdateStatusText.text += "Error: Playback log file does not exist! ->> " + filename + " <<"; Log(("Error: Playback log file does not exist! ->" + filename + "<")); Debug.LogError("Playback log file does not exist! " + filename); return; @@ -125,13 +129,8 @@ public void LoadNewFile(string filename) // Create an instance of StreamReader to read from a file. // The using statement also closes the StreamReader. - using StreamReader sr = new StreamReader(new FileStream(filename, FileMode.Open)); - // Read and display lines from the file until the end of the file is reached. - while (sr.ReadLine() is { } line) - { - loggedLines.Add(line); - } - LoadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; + loggedLines = File.ReadAllLines(filename); + loadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; Log("Finished loading log file. Lines: " + loggedLines.Count); } catch (Exception e) @@ -141,6 +140,15 @@ public void LoadNewFile(string filename) } } + private void Log(string msg) + { + if (loadingUpdateStatusText != null) + { + LoadingStatus_Show(); + loadingUpdateStatusText.text = string.Format($"{msg}"); + } + } + #region Parsers private static bool TryParseStringToVector3(string x, string y, string z, out Vector3 vector) { @@ -170,23 +178,23 @@ private static bool TryParseStringToVector3(string x, string y, string z, out Ve #region Available player actions public void Load() { -#if UNITY_EDITOR - LoadInEditor(); -#elif WINDOWS_UWP +#if WINDOWS_UWP LoadInUWP(); +#else + LoadInEditor(); #endif } private void LoadInEditor() { - LoadingUpdateStatusText.text = "Load: " + FileName; + loadingUpdateStatusText.text = "Load: " + FileName; LoadNewFile(FileName); } #if WINDOWS_UWP private async void LoadInUWP() { - LoadingUpdateStatusText.text = "[Load.1] " + FileName; + loadingUpdateStatusText.text = "[Load.1] " + FileName; await UWP_Load(); } #endif @@ -196,9 +204,9 @@ private string FileName get { #if WINDOWS_UWP - return "C:\\Data\\Users\\DefaultAccount\\Music\\MRTK_ET_Demo\\tester\\" + customFilename; + return "C:\\Data\\Users\\DefaultAccount\\Music\\MRTK_ET_Demo\\tester\\" + playbackLogFilename; #else - return Application.persistentDataPath + "/" + customFilename; + return Application.persistentDataPath + "/" + playbackLogFilename; #endif } } @@ -209,77 +217,11 @@ public bool IsPlaying get; } - public void Play() - { - IsPlaying = true; - lastUpdatedTime = DateTime.UtcNow; - deltaTimeToUpdateInMs = 0f; - EyeGazeVisualizer.gameObject.SetActive(true); - EyeGazeVisualizer.UnpauseApp(); - - if (HeadGazeVisualizer != null) - { - HeadGazeVisualizer.gameObject.SetActive(true); - HeadGazeVisualizer.UnpauseApp(); - } - } - - public void Pause() + public void StartPlayback() { - IsPlaying = false; - EyeGazeVisualizer.PauseApp(); - - if (HeadGazeVisualizer != null) - { - HeadGazeVisualizer.PauseApp(); - } - } - - public void Clear() - { - EyeGazeVisualizer.ResetVisualizations(); - HeadGazeVisualizer.ResetVisualizations(); - } - - public void ShowAllAndFreeze() - { - Debug.Log(">> ShowAllAndFreeze"); - ShowAllAndFreeze(EyeGazeVisualizer); - //ShowAllAndFreeze(HeadGazeVisualizer, InputSourceType.Head); ShowHeatmap(); } - private void ShowAllAndFreeze(InputPointerVisualizer visualizer) - { - if (visualizer != null) - { - visualizer.gameObject.SetActive(true); - -#if UNITY_EDITOR - Load(); -#elif WINDOWS_UWP - LoadingUpdateStatusText.text = "[Load.2] " + FileName; - bool result = AsyncHelpers.RunSync(() => UWP_Load()); - LoadingUpdateStatusText.text = "[Load.2] Done. "; -#endif - LoadingUpdateStatusText.text = "Loading done. Visualize data..."; - - // Let's unpause the visualizer to make updates - visualizer.UnpauseApp(); - - // Let's make sure that the visualizer will show all data at once - visualizer.AmountOfSamples = loggedLines.Count; - - // Now let's populate the visualizer - for (int i = 0; i < loggedLines.Count; i++) - { - string[] split = loggedLines[i].Split(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.ToCharArray()); - UpdateEyeGazeSignal(split, visualizer); - } - visualizer.PauseApp(); - } - } - private void ShowHeatmap() { if (heatmapReferences != null && heatmapReferences.Length > 0) @@ -296,46 +238,8 @@ private void ShowHeatmap() StartCoroutine(PopulateHeatmap()); } } - - public TextMeshPro LoadingUpdateStatusText; - - private void LoadingStatus_Hide() - { - if (LoadingUpdateStatusText != null) - { - LoadingUpdateStatusText.gameObject.SetActive(true); - } - } - - private void LoadingStatus_Show() - { - if (LoadingUpdateStatusText != null) - { - if (!LoadingUpdateStatusText.gameObject.activeSelf) - LoadingUpdateStatusText.gameObject.SetActive(true); - } - } - - private void UpdateLoadingStatus(int now, int total) - { - if (LoadingUpdateStatusText != null) - { - LoadingStatus_Show(); - LoadingUpdateStatusText.text = string.Format($"Replay status: {100f * now / total:0}%"); - } - } - - private void Log(string msg) - { - if (LoadingUpdateStatusText != null) - { - LoadingStatus_Show(); - LoadingUpdateStatusText.text = string.Format($"{msg}"); - } - } - - - private static int counter = 0; + + private int counter = 0; private IEnumerator PopulateHeatmap() { const float maxTargetingDistInMeters = 10f; @@ -372,115 +276,47 @@ private IEnumerator UpdateStatus(float updateFrequency) LoadingStatus_Hide(); } - private static Ray? GetEyeRay(IReadOnlyList split) - { - return GetRay(split[9], split[10], split[11], split[12], split[13], split[14]); - } - - private static Ray? GetRay(string originX, string originY, string originZ, string dirX, string dirY, string dirZ) + private void LoadingStatus_Hide() { - bool isValidVec1 = TryParseStringToVector3(originX, originY, originZ, out Vector3 origin); - bool isValidVec2 = TryParseStringToVector3(dirX, dirY, dirZ, out Vector3 dir); - - if (isValidVec1 && isValidVec2) + if (loadingUpdateStatusText != null) { - return new Ray(origin, dir); + loadingUpdateStatusText.gameObject.SetActive(true); } - return null; - } - #endregion - - #region Handle data replay - private bool DataIsLoaded - { - get { return loggedLines.Count > 0; } } - private DateTime lastUpdatedTime; - private float deltaTimeToUpdateInMs; - private float lastTimestampInMs; - - private void UpdateTimestampForNextReplay(IReadOnlyList split) + private void LoadingStatus_Show() { - if (float.TryParse(split[2], out float timestampInMs)) + if (loadingUpdateStatusText != null) { - lastUpdatedTime = DateTime.UtcNow; - deltaTimeToUpdateInMs = timestampInMs - lastTimestampInMs; - lastTimestampInMs = timestampInMs; + if (!loadingUpdateStatusText.gameObject.activeSelf) + loadingUpdateStatusText.gameObject.SetActive(true); } } - private static void UpdateEyeGazeSignal(IReadOnlyListsplit, InputPointerVisualizer visualizer) + private void UpdateLoadingStatus(int now, int total) { - Ray? ray = GetEyeRay(split); - if (ray.HasValue) + if (loadingUpdateStatusText != null) { - visualizer.UpdateDataVis(new Ray(ray.Value.origin, ray.Value.direction)); + LoadingStatus_Show(); + loadingUpdateStatusText.text = $"Replay status: {100f * now / total:0}%"; } } - private int replayIndex = 0; - private bool replayNotStartedYet = true; - public int NumSamples = 30; - - [SerializeField, Range(0f, 10.0f)] - private float replaySpeed = 1f; - - private void Update() + private static Ray? GetEyeRay(IReadOnlyList split) { - // First, let's checked if we're paused - if (IsPlaying) - { - // Second, let's check that it's time to add a new data point - if ((DateTime.UtcNow - lastUpdatedTime).TotalMilliseconds * replaySpeed > deltaTimeToUpdateInMs) - { - PlayNext(); - } - } + return GetRay(split[9], split[10], split[11], split[12], split[13], split[14]); } - private void PlayNext() + private static Ray? GetRay(string originX, string originY, string originZ, string dirX, string dirY, string dirZ) { - // Have we started the replay yet? - if (replayNotStartedYet) - { - replayNotStartedYet = false; - replayIndex = 0; - - if (!DataIsLoaded) - { - Load(); - } - - // Let's unpause the visualizer to make updates - // Show only a certain amount of data at once - if (EyeGazeVisualizer != null) - { - EyeGazeVisualizer.UnpauseApp(); - EyeGazeVisualizer.AmountOfSamples = NumSamples; - } - - if (HeadGazeVisualizer != null) - { - HeadGazeVisualizer.UnpauseApp(); - HeadGazeVisualizer.AmountOfSamples = NumSamples; - } - } + bool isValidVec1 = TryParseStringToVector3(originX, originY, originZ, out Vector3 origin); + bool isValidVec2 = TryParseStringToVector3(dirX, dirY, dirZ, out Vector3 dir); - // Now let's populate the visualizer step by step - if (replayIndex < loggedLines.Count) - { - string[] split = loggedLines[replayIndex].Split(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.ToCharArray()); - UpdateEyeGazeSignal(split, EyeGazeVisualizer); - UpdateTimestampForNextReplay(split); - replayIndex++; - } - else + if (isValidVec1 && isValidVec2) { - LoadingUpdateStatusText.text = "Replay done!"; - Pause(); - replayNotStartedYet = true; + return new Ray(origin, dir); } + return null; } #endregion } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs index 400ff8dedb9..3db84cfcfb2 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs @@ -2,65 +2,111 @@ // Licensed under the MIT License. using System; -using System.IO; +using System.Collections.Generic; using System.Text; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.Examples { + /// + /// + /// [AddComponentMenu("Scripts/MRTK/Examples/UserInputRecorder")] - public class UserInputRecorder : CustomInputLogger + public class UserInputRecorder : MonoBehaviour { - public string FilenameToUse = $"test{Path.AltDirectorySeparatorChar}folder"; + [SerializeField] + private string filenameToUse = "test/folder"; + + [SerializeField] + private bool addTimestampToLogfileName = false; + + private FileInputLogger fileLogger = null; [SerializeField] private LogStructure logStructure = null; - private bool automaticLogging = true; + [SerializeField] + private string userName = "tester"; + + [SerializeField] + private string sessionDescription = "Session00"; - #region Singleton - private static UserInputRecorder instance; - public static UserInputRecorder Instance + private string dataFormat; + private DateTime timerStart; + + private void OnEnable() + { + fileLogger = new FileInputLogger(userName, Filename); + timerStart = DateTime.Now; + fileLogger.AppendLog(GetHeader()); + } + + private void OnDisable() + { + fileLogger.Dispose(); + fileLogger = null; + } + + private void Update() + { + object[] data = MergeObjArrays(GetData_Part1(), logStructure.GetData()); + fileLogger.AppendLog(string.Format(dataFormat, data)); + } + + private static string FormattedTimeStamp { get { - if (instance == null) - { - instance = FindObjectOfType(); - } - return instance; + return DateTime.Now.ToString("yMMddHHmmss"); } } - #endregion - public override string GetHeader() + private string GetFileName() + { + return !string.IsNullOrEmpty(filenameToUse) ? filenameToUse : $"{sessionDescription}-{userName}"; + } + + private string Filename + { + get { return addTimestampToLogfileName ? FilenameWithTimestamp : FilenameNoTimestamp; } + } + + private string FilenameWithTimestamp + { + get { return $"{FormattedTimeStamp}_{FilenameNoTimestamp}.csv"; } + } + + private string FilenameNoTimestamp + { + get { return GetFileName() + ".csv"; } + } + + private string GetHeader() { if (logStructure != null) { string[] headerColumns = logStructure.GetHeaderColumns(); - string headerFormat = GetStringFormat(headerColumns); - return string.Format(headerFormat, headerColumns); + dataFormat = GetStringFormat(headerColumns); + return string.Format(dataFormat, headerColumns); } return ""; } - // Todo: Put into BasicLogger? protected object[] GetData_Part1() { object[] data = { // UserId - UserName, + userName, // SessionType sessionDescription, // Timestamp - (DateTime.UtcNow - TimerStart).TotalMilliseconds + (DateTime.UtcNow - timerStart).TotalMilliseconds }; return data; } - // Todo: Put into generic utils class? public object[] MergeObjArrays(object[] part1, object[] part2) { object[] data = new object[part1.Length + part2.Length]; @@ -69,52 +115,15 @@ public object[] MergeObjArrays(object[] part1, object[] part2) return data; } - protected override string GetFileName() - { - return !string.IsNullOrEmpty(FilenameToUse) ? FilenameToUse : $"{sessionDescription}-{UserName}"; - } - - public static string GetStringFormat(object[] data) + private static string GetStringFormat(IReadOnlyCollection data) { StringBuilder strFormat = new StringBuilder(); - for (int i = 0; i < data.Length - 1; i++) + for (int i = 0; i < data.Count - 1; i++) { strFormat.Append("{" + i + "}" + System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator + " "); } - strFormat.Append("{" + (data.Length - 1) + "}"); + strFormat.Append("{" + (data.Count - 1) + "}" + Environment.NewLine); return strFormat.ToString(); } - - public void UpdateLog() - { - if (Instance != null && IsLogging) - { - if (logStructure != null) - { - object[] data = MergeObjArrays(GetData_Part1(), logStructure.GetData()); - string data_format = GetStringFormat(data); - Instance.CustomAppend(string.Format(data_format, data)); - } - } - } - - private void Update() - { - if (automaticLogging) - { - UpdateLog(); - } - } - - public override void OnDestroy() - { - // Disable listening to user input - if (Instance != null) - { - Instance.StopLoggingAndSave(); - } - - base.OnDestroy(); - } } } From b564464da7988eb8e2bb903411aa0e55ac1c6f1a Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Tue, 4 Jul 2023 14:16:32 -0300 Subject: [PATCH 4/9] MRH3-62 Eye Tracking Examples Feedback - Removed InputPointerVisualizer, ParticleHeatmap, and ParticleHeapmapParticleData Co-authored-by: Amelia Mesdag --- .../Visualizer/InputPointerVisualizer.cs | 372 ------------------ .../Visualizer/InputPointerVisualizer.cs.meta | 11 - .../EyeTracking/Visualizer/ParticleHeatmap.cs | 81 ---- .../Visualizer/ParticleHeatmap.cs.meta | 11 - .../Visualizer/ParticleHeatmapParticleData.cs | 16 - .../ParticleHeatmapParticleData.cs.meta | 11 - 6 files changed, 502 deletions(-) delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs.meta delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs.meta delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs delete mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs.meta diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs deleted file mode 100644 index bb6296bcf9e..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using UnityEngine; - -namespace Microsoft.MixedReality.Toolkit.Examples -{ - using Input; - using System; - - /// - /// This visualizer can be used to represent pointer input data, e.g., from a handheld controller, - /// from hand, head or eye tracking. In general, it assumes a pointing origin and direction, - /// - [AddComponentMenu("Scripts/MRTK/Examples/InputPointerVisualizer")] - public class InputPointerVisualizer : MonoBehaviour - { - public enum VisModes - { - ShowAll, - ShowOnlyDestinations, - ShowNone - } - - [SerializeField] - private bool useLiveInputStream = false; - - private bool showOrigins = false; - private bool showDestinations = false; - private bool showLinkD2D = false; // Destination to destination - private bool showLinkO2D = false; // Origin to destination - - public VisModes ShowVisMode; - private VisModes showVisMode; // Using a private showTrace to detect when the item is changed in the Editor to trigger an vis update - - [SerializeField] - private bool onlyShowForHitTargets = false; - - [SerializeField] - [Tooltip("Template for visualizing vector origin, e.g., a colored sphere.")] - private ParticleHeatmap templateOrigins = null; - - [SerializeField] - [Tooltip("Template for visualizing hit pos, e.g., a colored sphere.")] - private ParticleHeatmap templateDestinations = null; - - [SerializeField] - [Tooltip("Template for visualizing connecting lines between vector origins - Should be a line renderer.")] - private GameObject templateLinkOrigToOrig = null; - - [SerializeField] - [Tooltip("Template for visualizing connecting lines between vector destinations - Should be a line renderer.")] - private GameObject templateLinkDestToDest = null; - - [SerializeField] - [Tooltip("Template for visualizing the vector between vector origin and destination - Should be a line renderer.")] - private GameObject templateLinkOrigToDest = null; - - [SerializeField] - [Tooltip("Distance to default to in case of no hit target.")] - private float cursorDist = 2f; - - [SerializeField] - private FuzzyGazeInteractor gazeInteractor; - - public int numSamples = 20; // Sample-based. Better to make it time-based. - public TextMesh textOutput; - - // Private variables - private ParticleHeatmap samplesOrigins; - private ParticleHeatmap samplesDestinations; - - private GameObject[] samplesLinkOrigToOrig; - private GameObject[] samplesLinkDestToDest; - private GameObject[] samplesLinkOrigToDest; - - private int currentItemIndex = 0; - private VisModes rememberState = VisModes.ShowOnlyDestinations; - private bool isPaused = false; - private int numberOfTraceSamples; - - private void Start() - { - AmountOfSamples = numSamples; - - if (textOutput != null) - textOutput.text = ""; - - SetActive_DataVis(ShowVisMode); - - // Init visualizations - ResetVisualizations(); - } - - public void ResetVisualizations() - { - ResetVis(); - Debug.Log(">>INIT VIS ARRAY " + numberOfTraceSamples); - InitPointClouds(ref samplesOrigins, templateOrigins); - InitPointClouds(ref samplesDestinations, templateDestinations); - InitVisArrayObj(ref samplesLinkOrigToOrig, templateLinkOrigToOrig, numberOfTraceSamples); - InitVisArrayObj(ref samplesLinkDestToDest, templateLinkDestToDest, numberOfTraceSamples); - InitVisArrayObj(ref samplesLinkOrigToDest, templateLinkOrigToDest, numberOfTraceSamples); - } - - private void InitPointClouds(ref ParticleHeatmap pointCloud, ParticleHeatmap templateParticleSystem) - { - if (templateParticleSystem != null) - { - // Initialize particle system to represent loaded point cloud data - Debug.Log(">>InitPointClouds 02"); - pointCloud = templateParticleSystem; - - } - else - pointCloud = null; - } - - private void InitVisArrayObj(ref GameObject[] array, GameObject template, int numOfSamples) - { - if (template != null) - { - // Initialize array of game objects to represent loaded data - array = new GameObject[numOfSamples]; - - // Instantiate copies of the provided template at (0,0,0) - later we simply change the position - for (int i = 0; i < numberOfTraceSamples; i++) - { - array[i] = Instantiate(template, Vector3.zero, Quaternion.identity) as GameObject; - array[i].transform.SetParent(transform, false); - } - } - else - { - array = null; - } - } - - private void ResetVis() - { - ResetPointCloudVis(ref samplesOrigins); - ResetPointCloudVis(ref samplesDestinations); - - ResetVis(ref samplesLinkOrigToOrig); - ResetVis(ref samplesLinkDestToDest); - ResetVis(ref samplesLinkOrigToDest); - } - - private void ResetVis(ref GameObject[] array) - { - if (array != null) - { - for (int i = array.Length - 1; i >= 0; i--) - { - Destroy(array[i]); - } - } - } - - private void ResetPointCloudVis(ref ParticleHeatmap pointCloud) - { - if (pointCloud != null) - { - pointCloud.HideHeatmap(); - } - } - - private void SetActive_DataVis(VisModes visMode) - { - Debug.Log("SetDataVis: " + visMode); - - showVisMode = visMode; - switch (visMode) - { - case VisModes.ShowNone: - SetActive_DataVis(false, false, false, false, false); - break; - case VisModes.ShowOnlyDestinations: - SetActive_DataVis(false, true, false, true, false); - break; - case VisModes.ShowAll: - SetActive_DataVis(true, true, true, true, true); - break; - } - } - - private void SetActive_DataVis(bool showOrigins, bool showDest, bool showO2O, bool showD2D, bool showO2D) - { - this.showOrigins = showOrigins; - showDestinations = showDest; - showLinkO2D = showO2O; - showLinkD2D = showD2D; - showLinkO2D = showO2D; - - SetActive_PointCloudVis(ref samplesOrigins, showOrigins); - SetActive_PointCloudVis(ref samplesDestinations, showDest); - - SetActive_DataVis(ref samplesLinkOrigToOrig, showO2O); - - Debug.Log("Set up D2D links: " + showD2D); - SetActive_DataVis(ref samplesLinkDestToDest, showD2D); - - if (samplesLinkOrigToDest != null) - { - for (int i = 0; i < samplesLinkOrigToDest.Length; i++) - { - samplesLinkOrigToDest[i].SetActive(true); - } - } - SetActive_DataVis(ref samplesLinkOrigToDest, showO2D); - } - - - private void SetActive_DataVis(ref GameObject[] array, bool activate) - { - if (array != null) - { - for (int i = 0; i < array.Length; i++) - { - array[i].SetActive(activate); - } - } - } - - private void SetActive_PointCloudVis(ref ParticleHeatmap pointCloud, bool activate) - { - if (pointCloud != null) - { - pointCloud.enabled = true; - pointCloud.ShowHeatmap(); - } - } - - private void UpdateVis_PointCloud(ref ParticleHeatmap pointCloud, int index, Vector3 newPos, bool show) - { - if (pointCloud != null) - { - pointCloud.SetParticle(newPos); - pointCloud.DisplayParticles(); - } - } - - private void UpdateConnectorLines(ref GameObject[] array, int index, Vector3 fromPos, Vector3 toPos, bool show) - { - array[index].SetActive(show); - LineRenderer line = array[index].GetComponent(); - - line.SetPosition(0, fromPos); - line.SetPosition(1, toPos); - } - - Vector3? _lastDestination; - public void UpdateDataVis(Ray cursorRay) - { - currentItemIndex++; - if (currentItemIndex >= numberOfTraceSamples) - currentItemIndex = 0; - - try - { - // Vector origin - UpdateVis_PointCloud(ref samplesOrigins, currentItemIndex, cursorRay.origin, showOrigins); - - // Vector destination / hit pos - Vector3? v = PerformHitTest(cursorRay); - - if (!v.HasValue && !onlyShowForHitTargets) - { - v = cursorRay.origin + cursorRay.direction.normalized * cursorDist; - } - - UpdateVis_PointCloud(ref samplesDestinations, currentItemIndex, v.Value, showDestinations); - - - // ... Vector destinations - if (samplesDestinations != null && samplesLinkDestToDest != null) - { - Vector3? pos1 = _lastDestination; - Vector3? pos2 = v.Value; - - if ((pos1.HasValue) && (pos2.HasValue)) - { - UpdateConnectorLines(ref samplesLinkDestToDest, currentItemIndex, pos1.Value, pos2.Value, showLinkD2D); - } - } - - _lastDestination = v.Value; - if (samplesDestinations != null && samplesLinkOrigToDest != null) - { - Vector3? pos1 = cursorRay.origin; - Vector3? pos2 = v.Value; - - if (pos1.HasValue && pos2.HasValue) - { - UpdateConnectorLines(ref samplesLinkOrigToDest, currentItemIndex, pos1.Value, pos2.Value, showLinkO2D); - } - } - } - catch (Exception exc) - { - Debug.Log("[CustomVisualizer] Exception: " + exc); - } - } - - private Vector3? PerformHitTest(Ray ray) - { - if (Physics.Raycast(ray, out RaycastHit hitInfo)) - { - return hitInfo.point; - } - - return null; - } - - private void Update() - { - if (ShowVisMode != showVisMode) - { - SetActive_DataVis(ShowVisMode); - } - - if (!isPaused && useLiveInputStream) - { - UpdateDataVis(new Ray(gazeInteractor.rayOriginTransform.position, gazeInteractor.rayOriginTransform.forward)); - } - } - - public int AmountOfSamples - { - get { return numberOfTraceSamples; } - set - { - numberOfTraceSamples = value; - ResetVisualizations(); - } - } - - public void ToggleAppState() - { - SetAppState(!isPaused); - } - - public void PauseApp() - { - SetAppState(true); - } - - public void UnpauseApp() - { - SetAppState(false); - } - - public void SetAppState(bool pauseIt) - { - isPaused = pauseIt; - if (textOutput != null) - { - if (pauseIt) - { - rememberState = showVisMode; - textOutput.text = "Paused..."; - SetActive_DataVis(VisModes.ShowAll); - } - else - { - textOutput.text = ""; - SetActive_DataVis(rememberState); - } - } - } - } -} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs.meta deleted file mode 100644 index 74f6f0a6431..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/InputPointerVisualizer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d181de5344315d24b8bce19d973451c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs deleted file mode 100644 index 83d1d5b90ac..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Collections.Generic; -using UnityEngine; - -namespace Microsoft.MixedReality.Toolkit.Examples -{ - [RequireComponent(typeof(ParticleSystem))] - [AddComponentMenu("Scripts/MRTK/Examples/ParticleHeatmap")] - public class ParticleHeatmap : MonoBehaviour - { - [SerializeField] - private int maxNumberOfParticles = 100; - - [SerializeField] - private float minParticleSize = 0.01f; - - [SerializeField] - private float maxParticleSize = 0.5f; - - private int particleDecalDataIndex; - private ParticleSystem particleSys; - private ParticleSystem.EmissionModule emissionModule; - private List particleData; - - private void Start() - { - // Initialize particle data handlers - particleSys = GetComponent(); - emissionModule = particleSys.emission; - particleData = new List(); - } - - public void SetParticle(Vector3 pos) - { - if (particleDecalDataIndex >= maxNumberOfParticles) - { - particleDecalDataIndex = 0; - } - - ParticleHeatmapParticleData newParticle = new ParticleHeatmapParticleData(); - newParticle.position = pos; - newParticle.radiusInMeter = Random.Range(minParticleSize, maxParticleSize); - - if (particleDecalDataIndex >= particleData.Count) - { - particleData.Add(newParticle); - } - else - { - particleData[particleDecalDataIndex] = newParticle; - } - - particleDecalDataIndex++; - } - - public void DisplayParticles() - { - ParticleSystem.Particle[] particleArray = new ParticleSystem.Particle[particleData.Count]; - for (int i = 0; i < particleData.Count; i++) - { - particleArray[i].position = particleData[i].position; - particleArray[i].startColor = particleData[i].color; - particleArray[i].startSize = particleData[i].radiusInMeter; - } - - particleSys.SetParticles(particleArray, particleArray.Length); - } - - public void ShowHeatmap() - { - emissionModule.enabled = true; - } - - public void HideHeatmap() - { - emissionModule.enabled = false; - } - } -} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs.meta deleted file mode 100644 index d1782b73148..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmap.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7bd6a1490de28eb45bda52cfcc3237d5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs deleted file mode 100644 index d5c71e7020b..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using UnityEngine; - -namespace Microsoft.MixedReality.Toolkit.Examples -{ - public class ParticleHeatmapParticleData - { - public Vector3 position; - public Vector3 rotation; - public float radiusInMeter; - public float intensity; - public Color color; - } -} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs.meta deleted file mode 100644 index dd361db2340..00000000000 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/ParticleHeatmapParticleData.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f1512405500749646bdd64746491e6ef -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From c05756872f5ccc362d162c6418d13ee731c9fb1b Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Tue, 4 Jul 2023 19:12:27 -0300 Subject: [PATCH 5/9] MRH3-62 Eye Tracking Examples Feedback - Added Pause/Resume functionality - Add documentation to eye gaze visualizer classes --- .../Visualizer/Controls.prefab | 901 +++++++++++++++++- .../EyeTrackingExample-05-Visualizer.unity | 187 ++-- .../EyeTracking/Visualizer/FileInputLogger.cs | 23 +- .../Visualizer/LogStructureEyeGaze.cs | 4 +- .../Visualizer/UserInputPlayback.cs | 130 ++- .../Visualizer/UserInputRecorder.cs | 29 +- .../Visualizer/UserInputRecorderFeedback.cs | 15 + .../UserInputRecorderUIController.cs | 71 +- 8 files changed, 1108 insertions(+), 252 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab index c31baab5837..bd13b428859 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab @@ -1,5 +1,243 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &715919861 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 715919862} + m_Layer: 0 + m_Name: ResumePlayback + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &715919862 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 715919861} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8237818351390515726} + - {fileID: 1176919169} + m_Father: {fileID: 4198762078266477014} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1176919168 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1176919169} + - component: {fileID: 1176919171} + - component: {fileID: 1176919170} + m_Layer: 0 + m_Name: ResumeSubtitle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1176919169 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176919168} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.0039999434} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 715919862} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.052, y: -0.0282} + m_SizeDelta: {x: 20, y: 1.86439} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &1176919171 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176919168} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &1176919170 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176919168} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Resume Playback + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + m_sharedMaterial: {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 0.12 + m_fontSizeBase: 0.12 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + _SortingLayer: 0 + _SortingLayerID: 0 + _SortingOrder: 0 + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 1176919171} + m_maskType: 0 +--- !u!1 &191985091076322603 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8189025005218568427} + m_Layer: 0 + m_Name: PausePlayback + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &8189025005218568427 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191985091076322603} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 847283648898560367} + - {fileID: 3876539496687166768} + m_Father: {fileID: 4198762078266477014} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &760708550725870779 GameObject: m_ObjectHideFlags: 0 @@ -47,10 +285,90 @@ MeshRenderer: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 760708550725870779} + m_GameObject: {fileID: 760708550725870779} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9bcfe6e80e7f20c4c95aa47d2107fd7f, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &1021001469993947310 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3876539496687166768} + - component: {fileID: 9019561472862463284} + - component: {fileID: 7475168624257871200} + m_Layer: 0 + m_Name: PauseSubtitle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3876539496687166768 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1021001469993947310} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.0039999434} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8189025005218568427} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.052, y: -0.0282} + m_SizeDelta: {x: 20, y: 1.86439} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &9019561472862463284 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1021001469993947310} m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 m_DynamicOccludee: 1 m_StaticShadowCaster: 0 m_MotionVectors: 1 @@ -61,7 +379,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 9bcfe6e80e7f20c4c95aa47d2107fd7f, type: 2} + - {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -83,6 +401,98 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &7475168624257871200 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1021001469993947310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Pause Playback + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + m_sharedMaterial: {fileID: -1005824763306460071, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 0.12 + m_fontSizeBase: 0.12 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + _SortingLayer: 0 + _SortingLayerID: 0 + _SortingOrder: 0 + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 9019561472862463284} + m_maskType: 0 --- !u!1 &1489465439754421922 GameObject: m_ObjectHideFlags: 0 @@ -114,6 +524,8 @@ Transform: - {fileID: 1193512509479148198} - {fileID: 5040661256948473030} - {fileID: 4170012658089045370} + - {fileID: 8189025005218568427} + - {fileID: 715919862} m_Father: {fileID: 5853303421825090637} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -561,9 +973,9 @@ MonoBehaviour: m_EditorClassIdentifier: buttonStartRecording: {fileID: 8650713101073464895} buttonStopRecording: {fileID: 6802997350238223167} - buttonStartPlaybackInactive: {fileID: 0} - buttonStartPlayback: {fileID: 0} - buttonPausePlayback: {fileID: 0} + buttonStartPlayback: {fileID: 8310050747605233910} + buttonPausePlayback: {fileID: 191985091076322603} + buttonResumePlayback: {fileID: 8237818353018430703} --- !u!114 &2087141182152323438 MonoBehaviour: m_ObjectHideFlags: 0 @@ -571,16 +983,16 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6848819235249797219} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 7a97caac99350c446a783a1bc3e9bf1e, type: 3} m_Name: m_EditorClassIdentifier: - AddTimestampToLogfileName: 0 - UserName: tester - sessionDescription: Session00 - FilenameToUse: mrtk_log_mostRecentET + filenameToUse: test + addTimestampToLogfileName: 0 logStructure: {fileID: 9111033687875367441} + userName: tester + sessionDescription: Session00 --- !u!114 &7861801676748397993 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1134,7 +1546,7 @@ GameObject: m_Component: - component: {fileID: 4170012658089045370} m_Layer: 0 - m_Name: Playback + m_Name: StartPlayback m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1175,21 +1587,216 @@ GameObject: m_IsActive: 1 --- !u!4 &1193512509479148198 Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8650713101073464895} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5243915654612318504} + - {fileID: 7887614037648120092} + m_Father: {fileID: 4198762078266477014} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1506125274296913025 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 8189025005218568427} + m_Modifications: + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: speechRecognitionKeyword + value: play + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.size + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 5685716680725385779} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target + value: + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Target + value: + objectReference: {fileID: 7861801676748397993} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: PauseReplay + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName + value: PauseHeatmapPlayback + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName + value: PauseReplay + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderUIController, + Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputPlayback, Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderFeedback, Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 2244185730325434482, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_Name + value: PauseHeatmap + objectReference: {fileID: 0} + - target: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.x + value: 0.051999986 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.z + value: -0.0057 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3830872527647582975, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4659777866328155393, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_text + value: "\uF75B" + objectReference: {fileID: 0} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_sharedMaterial + value: + objectReference: {fileID: 5762245003366665926, guid: 9b0d0ee11ff70b04d901a29b519cbaa0, type: 2} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_hasFontAssetChanged + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6663514093482171836, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7797914476011694290, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: currentIconName + value: Icon 135 + objectReference: {fileID: 0} + - target: {fileID: 7855682163667943843, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 5762245003366665926, guid: 9b0d0ee11ff70b04d901a29b519cbaa0, type: 2} + - target: {fileID: 7867802180497734224, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8392048804767038291, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd0f0697f0939504389ec612388f609a, type: 3} +--- !u!4 &847283648898560367 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + m_PrefabInstance: {fileID: 1506125274296913025} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8650713101073464895} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 5243915654612318504} - - {fileID: 7887614037648120092} - m_Father: {fileID: 4198762078266477014} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1001 &6332855513976014022 PrefabInstance: m_ObjectHideFlags: 0 @@ -1215,7 +1822,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode - value: 1 + value: 6 objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode @@ -1251,7 +1858,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName - value: StartLogging + value: set_enabled objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName @@ -1264,14 +1871,17 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.CustomInputLogger, - Assembly-CSharp + value: UnityEngine.Behaviour, UnityEngine objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputRecorderFeedback, Assembly-CSharp objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_BoolArgument + value: 1 + objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName value: UnityEngine.Object, UnityEngine @@ -1396,7 +2006,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.size - value: 2 + value: 3 objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Mode @@ -1417,11 +2027,11 @@ PrefabInstance: - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target value: - objectReference: {fileID: 7861801676748397993} + objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Target value: - objectReference: {fileID: 0} + objectReference: {fileID: 7861801676748397993} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_CallState value: 2 @@ -1440,22 +2050,24 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName + value: StartPlayback + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName value: StartReplay objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputRecorderUIController, + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderUIController, Assembly-CSharp objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputRecorderFeedback, - Assembly-CSharp + value: Microsoft.MixedReality.Toolkit.Examples.UserInputPlayback, Assembly-CSharp objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputRecorderFeedback, - Assembly-CSharp + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderFeedback, Assembly-CSharp objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName @@ -1465,6 +2077,10 @@ PrefabInstance: propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName value: UnityEngine.Object, UnityEngine objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} - target: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: m_Name value: ShowHeatmap @@ -1565,7 +2181,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode - value: 1 + value: 6 objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode @@ -1601,7 +2217,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName - value: StopLoggingAndSave + value: set_enabled objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName @@ -1614,8 +2230,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.CustomInputLogger, - Assembly-CSharp + value: UnityEngine.Behaviour, UnityEngine objectReference: {fileID: 0} - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName @@ -1729,3 +2344,203 @@ Transform: m_CorrespondingSourceObject: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} m_PrefabInstance: {fileID: 7887614037795750464} m_PrefabAsset: {fileID: 0} +--- !u!1001 &7887614037859475424 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 715919862} + m_Modifications: + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: speechRecognitionKeyword + value: play + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.size + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 5685716680725385779} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target + value: + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Target + value: + objectReference: {fileID: 7861801676748397993} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_CallState + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: ResumeReplay + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName + value: ResumeHeatmapPlayback + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName + value: ResumeReplay + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderUIController, + Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputPlayback, Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName + value: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderFeedback, Assembly-CSharp + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 1503546110793399400, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} + - target: {fileID: 2244185730325434482, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_Name + value: ResumeHeatmap + objectReference: {fileID: 0} + - target: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.x + value: 0.051999986 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalPosition.z + value: -0.0057 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3830872527647582975, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4659777866328155393, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_text + value: "\uF608" + objectReference: {fileID: 0} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_sharedMaterial + value: + objectReference: {fileID: 5762245003366665926, guid: 9b0d0ee11ff70b04d901a29b519cbaa0, type: 2} + - target: {fileID: 6397459067767180594, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_hasFontAssetChanged + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6663514093482171836, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7797914476011694290, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: currentIconName + value: Icon 123 + objectReference: {fileID: 0} + - target: {fileID: 7855682163667943843, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 5762245003366665926, guid: 9b0d0ee11ff70b04d901a29b519cbaa0, type: 2} + - target: {fileID: 7867802180497734224, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8392048804767038291, guid: cd0f0697f0939504389ec612388f609a, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd0f0697f0939504389ec612388f609a, type: 3} +--- !u!4 &8237818351390515726 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} + m_PrefabInstance: {fileID: 7887614037859475424} + m_PrefabAsset: {fileID: 0} +--- !u!1 &8237818353018430703 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} + m_PrefabInstance: {fileID: 7887614037859475424} + m_PrefabAsset: {fileID: 0} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity index 3e959a19ed1..7fd5f97e322 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity @@ -703,6 +703,11 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &715919861 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 715919861, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + m_PrefabInstance: {fileID: 7887614037481751899} + m_PrefabAsset: {fileID: 0} --- !u!1 &870610048 GameObject: m_ObjectHideFlags: 0 @@ -1146,7 +1151,35 @@ MonoBehaviour: - {fileID: 1018849797} - {fileID: 1524931721350790071} loadingUpdateStatusText: {fileID: 947746751} - replaySpeed: 1 + onPlaybackCompleted: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 4345256063198200088} + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderFeedback, + Assembly-CSharp + m_MethodName: PlaybackCompleted + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 4345256063198200090} + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.UserInputRecorderUIController, + Assembly-CSharp + m_MethodName: ShowStartButton + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 --- !u!224 &1261404671 stripped RectTransform: m_CorrespondingSourceObject: {fileID: 3220012215463627515, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} @@ -1213,7 +1246,7 @@ PrefabInstance: m_Modifications: - target: {fileID: 7942278510844116557, guid: cea6f24b8f65d5444ba5379c831cce58, type: 3} propertyPath: m_RootOrder - value: 1 + value: 2 objectReference: {fileID: 0} - target: {fileID: 7942278510844116557, guid: cea6f24b8f65d5444ba5379c831cce58, type: 3} propertyPath: m_LocalPosition.x @@ -1562,7 +1595,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3220012215463627515, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} propertyPath: m_AnchoredPosition.x - value: 0.7706 + value: 0.807 objectReference: {fileID: 0} - target: {fileID: 3220012215463627515, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} propertyPath: m_AnchoredPosition.y @@ -1899,6 +1932,28 @@ Transform: m_CorrespondingSourceObject: {fileID: 5853303421825090637, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} m_PrefabInstance: {fileID: 7887614037481751899} m_PrefabAsset: {fileID: 0} +--- !u!114 &4345256063198200088 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 7861801676748397993, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + m_PrefabInstance: {fileID: 7887614037481751899} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 27406527dd719a842966cc058810b3d0, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &4345256063198200090 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 5685716680725385779, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + m_PrefabInstance: {fileID: 7887614037481751899} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5812ed0a484609c4aa8a0324c746f3b7, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1001 &6221313583953120647 PrefabInstance: m_ObjectHideFlags: 0 @@ -1971,26 +2026,14 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 870610049} m_Modifications: - - target: {fileID: 2087141182152323438, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: m_Enabled - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode - value: 6 - objectReference: {fileID: 0} - - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName - value: set_enabled - objectReference: {fileID: 0} - - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: UnityEngine.Behaviour, UnityEngine - objectReference: {fileID: 0} - - target: {fileID: 4845725528430786734, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_BoolArgument - value: 1 - objectReference: {fileID: 0} + - target: {fileID: 16747545106985193, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target + value: + objectReference: {fileID: 1232406737} + - target: {fileID: 5685716680725385779, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + propertyPath: buttonResumePlayback + value: + objectReference: {fileID: 715919861} - target: {fileID: 5853303421825090637, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: m_RootOrder value: 2 @@ -2039,109 +2082,17 @@ PrefabInstance: propertyPath: m_Name value: Controls objectReference: {fileID: 0} - - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Mode - value: 6 - objectReference: {fileID: 0} - - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName - value: set_enabled - objectReference: {fileID: 0} - - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: UnityEngine.Behaviour, UnityEngine - objectReference: {fileID: 0} - - target: {fileID: 8767316698063830568, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_BoolArgument - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.size - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Mode - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_Mode - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_Target - value: - objectReference: {fileID: 1232406737} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + - target: {fileID: 8767316698085532552, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target value: objectReference: {fileID: 1232406737} - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Target - value: - objectReference: {fileID: 1232406737} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_Target + propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target value: objectReference: {fileID: 1232406737} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_CallState - value: 2 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_CallState - value: 2 - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName - value: StartPlayback - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName - value: ShowAllAndFreeze - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_MethodName - value: Play - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_MethodName - value: Play - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.UserInputPlayback, Assembly-CSharp - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputPlayback, - Assembly-CSharp - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputPlayback, - Assembly-CSharp - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_TargetAssemblyTypeName - value: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.Logging.UserInputPlayback, - Assembly-CSharp - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[2].m_Arguments.m_ObjectArgumentAssemblyTypeName - value: UnityEngine.Object, UnityEngine - objectReference: {fileID: 0} - - target: {fileID: 8767316698221281973, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[3].m_Arguments.m_ObjectArgumentAssemblyTypeName - value: UnityEngine.Object, UnityEngine - objectReference: {fileID: 0} - target: {fileID: 9111033687875367441, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: gazeInteractor value: objectReference: {fileID: 1517009107} - - target: {fileID: 9111033687875367441, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: _gazeInteractor - value: - objectReference: {fileID: 1517009107} - m_RemovedComponents: - - {fileID: 875359124282182997, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} + m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs index 1586d4283cc..4ced5129222 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs @@ -3,7 +3,6 @@ using System; using System.IO; -using System.Text; using UnityEngine; #if WINDOWS_UWP @@ -13,17 +12,16 @@ namespace Microsoft.MixedReality.Toolkit.Examples { /// - /// + /// Stores collected eye gaze data to a file. /// public class FileInputLogger : IDisposable { private bool disposed = false; private StreamWriter logFile = null; - private string userName; - - public FileInputLogger(string userName, string fileName) + + public FileInputLogger(string userNameFolder, string fileName) { - UserName = userName; + UserNameFolder = userNameFolder; #if WINDOWS_UWP await CreateNewLogFile(); @@ -50,16 +48,12 @@ public void Dispose() } /// - /// + /// A user folder to store logs file in UWP /// - public string UserName - { - get { return userName; } - set { userName = value; } - } + private string UserNameFolder { get; set; } #if WINDOWS_UWP - public string LogDirectory => "MRTK_ET_Demo/" + UserName; + public string LogDirectory => "MRTK_ET_Demo/" + UserNameFolder; private StorageFile logFile; private StorageFolder logRootFolder = KnownFolders.MusicLibrary; @@ -113,6 +107,9 @@ public async void AppendLog(string message) await FileIO.AppendTextAsync(logFile, message); } #else + /// + /// Appends a message to the log file. + /// public void AppendLog(string message) { logFile.Write(message); diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs index b89dec3c9dc..bc6f2d1a105 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/LogStructureEyeGaze.cs @@ -2,17 +2,17 @@ // Licensed under the MIT License. using UnityEngine; +using Microsoft.MixedReality.Toolkit.Input; namespace Microsoft.MixedReality.Toolkit.Examples { - using Input; - /// /// A CSV file logging structure for eye gaze data. /// [AddComponentMenu("Scripts/MRTK/Examples/LogStructureEyeGaze")] public class LogStructureEyeGaze : LogStructure { + [Tooltip("Reference to the FuzzyGazeInteractor in the scene")] [SerializeField] private FuzzyGazeInteractor gazeInteractor; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs index 861449d1275..5a12285f8ff 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs @@ -15,19 +15,32 @@ namespace Microsoft.MixedReality.Toolkit.Examples { + using UnityEngine.Events; + + /// + /// Allows the user to playback a recorded log file of eye gaze interactions with a heat map. + /// [AddComponentMenu("Scripts/MRTK/Examples/UserInputPlayback")] public class UserInputPlayback : MonoBehaviour { + [Tooltip("Filename of the log file to be replayed")] [SerializeField] private string playbackLogFilename = string.Empty; + [Tooltip("References to the heatmaps to show playback of eye gaze interactions")] [SerializeField] private DrawOnTexture[] heatmapReferences = null; + [Tooltip("Displays status updates for file loading and replay status")] [SerializeField] private TextMeshPro loadingUpdateStatusText; + [Tooltip("Event that is fired when playback of a log file has completed")] + [SerializeField] + private UnityEvent onPlaybackCompleted; + private IReadOnlyList loggedLines; + private Coroutine showHeatmapCoroutine; #if WINDOWS_UWP private StorageFolder uwpRootFolder = KnownFolders.MusicLibrary; @@ -43,6 +56,14 @@ private void Start() LoadingStatus_Hide(); } + private void Update() + { + if (IsPlaying && IsDataLoaded && counter < loggedLines.Count - 1) + { + UpdateLoadingStatus(counter, loggedLines.Count); + } + } + private void ResetCurrentStream() { loggedLines = null; @@ -104,7 +125,7 @@ private async Task UWP_ReadData(StorageFile logfile) } #endif - private bool DataIsLoaded + private bool IsDataLoaded { get { return loggedLines != null && loggedLines.Count > 0; } } @@ -115,11 +136,7 @@ private void LoadNewFile(string filename) try { -#if WINDOWS_UWP - if (!UnityEngine.Windows.File.Exists(filename)) -#else if (!File.Exists(filename)) -#endif { loadingUpdateStatusText.text += "Error: Playback log file does not exist! ->> " + filename + " <<"; Log(("Error: Playback log file does not exist! ->" + filename + "<")); @@ -139,16 +156,7 @@ private void LoadNewFile(string filename) Debug.Log("The file could not be read:\n" + e.Message); } } - - private void Log(string msg) - { - if (loadingUpdateStatusText != null) - { - LoadingStatus_Show(); - loadingUpdateStatusText.text = string.Format($"{msg}"); - } - } - + #region Parsers private static bool TryParseStringToVector3(string x, string y, string z, out Vector3 vector) { @@ -176,7 +184,7 @@ private static bool TryParseStringToVector3(string x, string y, string z, out Ve #endregion #region Available player actions - public void Load() + private void Load() { #if WINDOWS_UWP LoadInUWP(); @@ -184,7 +192,7 @@ public void Load() LoadInEditor(); #endif } - + private void LoadInEditor() { loadingUpdateStatusText.text = "Load: " + FileName; @@ -198,6 +206,22 @@ private async void LoadInUWP() await UWP_Load(); } #endif + /// + /// True while the GameObject is playing back eye gaze data from the log file. + /// + public bool IsPlaying + { + private set; + get; + } + + /// + /// Begins playback of the eye gaze data. + /// + public void StartPlayback() + { + ShowHeatmap(); + } private string FileName { @@ -210,34 +234,41 @@ private string FileName #endif } } - - public bool IsPlaying - { - private set; - get; - } - - public void StartPlayback() - { - ShowHeatmap(); - } - + private void ShowHeatmap() { if (heatmapReferences != null && heatmapReferences.Length > 0) { // First, let's load the data - if (!DataIsLoaded) + if (!IsDataLoaded) { Load(); } - counter = 0; + if (showHeatmapCoroutine != null) + StopCoroutine(showHeatmapCoroutine); - StartCoroutine(UpdateStatus(0.2f)); - StartCoroutine(PopulateHeatmap()); + IsPlaying = true; + counter = 0; + showHeatmapCoroutine = StartCoroutine(PopulateHeatmap()); } } + + /// + /// Pauses playback of the eye gaze data. + /// + public void PauseHeatmapPlayback() + { + IsPlaying = false; + } + + /// + /// Resumes playback of the eye gaze data. + /// + public void ResumeHeatmapPlayback() + { + IsPlaying = true; + } private int counter = 0; private IEnumerator PopulateHeatmap() @@ -261,21 +292,27 @@ private IEnumerator PopulateHeatmap() } } counter = i; - yield return null; + if (IsPlaying) + { + yield return null; + } + else + { + yield return new WaitUntil(() => IsPlaying); + } } } + + PlaybackCompleted(); } - private IEnumerator UpdateStatus(float updateFrequency) + private void PlaybackCompleted() { - while (counter < loggedLines.Count - 1) - { - UpdateLoadingStatus(counter, loggedLines.Count); - yield return new WaitForSeconds(updateFrequency); - } - LoadingStatus_Hide(); + IsPlaying = false; + ResetCurrentStream(); + onPlaybackCompleted.Invoke(); } - + private void LoadingStatus_Hide() { if (loadingUpdateStatusText != null) @@ -293,6 +330,15 @@ private void LoadingStatus_Show() } } + private void Log(string msg) + { + if (loadingUpdateStatusText != null) + { + LoadingStatus_Show(); + loadingUpdateStatusText.text = string.Format($"{msg}"); + } + } + private void UpdateLoadingStatus(int now, int total) { if (loadingUpdateStatusText != null) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs index 3db84cfcfb2..876293669ea 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs @@ -9,28 +9,33 @@ namespace Microsoft.MixedReality.Toolkit.Examples { /// - /// + /// Allows the user to record a log file of eye gaze interactions for playback at another time. + /// The log file is a CSV file and is created and written to while this behaviour is /// [AddComponentMenu("Scripts/MRTK/Examples/UserInputRecorder")] public class UserInputRecorder : MonoBehaviour { + [Tooltip("File name segment appended to the log file name")] [SerializeField] - private string filenameToUse = "test/folder"; + private string filenameToUse = "test"; + [Tooltip("Prepends a timestamp to the log file name if enabled")] [SerializeField] private bool addTimestampToLogfileName = false; - private FileInputLogger fileLogger = null; - + [Tooltip("The log structure to gather eye gaze samples from")] [SerializeField] private LogStructure logStructure = null; + [Tooltip("User name added to the log structure, and added to UWP file names and folder structure")] [SerializeField] private string userName = "tester"; + [Tooltip("Session description added to UWP file names")] [SerializeField] private string sessionDescription = "Session00"; + private FileInputLogger fileLogger = null; private string dataFormat; private DateTime timerStart; @@ -61,16 +66,11 @@ private static string FormattedTimeStamp } } - private string GetFileName() - { - return !string.IsNullOrEmpty(filenameToUse) ? filenameToUse : $"{sessionDescription}-{userName}"; - } - private string Filename { get { return addTimestampToLogfileName ? FilenameWithTimestamp : FilenameNoTimestamp; } } - + private string FilenameWithTimestamp { get { return $"{FormattedTimeStamp}_{FilenameNoTimestamp}.csv"; } @@ -81,6 +81,11 @@ private string FilenameNoTimestamp get { return GetFileName() + ".csv"; } } + private string GetFileName() + { + return !string.IsNullOrEmpty(filenameToUse) ? filenameToUse : $"{sessionDescription}-{userName}"; + } + private string GetHeader() { if (logStructure != null) @@ -93,7 +98,7 @@ private string GetHeader() return ""; } - protected object[] GetData_Part1() + private object[] GetData_Part1() { object[] data = { // UserId @@ -107,7 +112,7 @@ protected object[] GetData_Part1() return data; } - public object[] MergeObjArrays(object[] part1, object[] part2) + private object[] MergeObjArrays(object[] part1, object[] part2) { object[] data = new object[part1.Length + part2.Length]; part1.CopyTo(data, 0); diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderFeedback.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderFeedback.cs index 208fc62d236..41488041239 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderFeedback.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderFeedback.cs @@ -7,12 +7,17 @@ namespace Microsoft.MixedReality.Toolkit.Examples { + /// + /// This script displays on screen status updates user recording and playback control system. + /// [AddComponentMenu("Scripts/MRTK/Examples/UserInputRecorderFeedback")] public class UserInputRecorderFeedback : MonoBehaviour { + [Tooltip("Textfield that displays status updates")] [SerializeField] private TextMeshPro statusText = null; + [Tooltip("The duration an update will be displayed before it is hidden")] [SerializeField] private float maxShowDurationInSeconds = 2f; @@ -75,6 +80,16 @@ public void PauseReplay() { UpdateStatusText("Replay stopped!"); } + + public void ResumeReplay() + { + UpdateStatusText("Replay resumed!"); + } + + public void PlaybackCompleted() + { + UpdateStatusText("Playback Completed!"); + } #endregion } } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderUIController.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderUIController.cs index dc0aac9c0f2..bfe01566d60 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderUIController.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorderUIController.cs @@ -5,36 +5,50 @@ namespace Microsoft.MixedReality.Toolkit.Examples { + /// + /// This script controls the UI state of the user recording and playback control system. + /// [AddComponentMenu("Scripts/MRTK/Examples/UserInputRecorderUIController")] public class UserInputRecorderUIController : MonoBehaviour { + [Tooltip("Root GameObject that allows the user to start a new recording")] [SerializeField] private GameObject buttonStartRecording = null; + [Tooltip("Root GameObject that allows the user to stop a recording")] [SerializeField] private GameObject buttonStopRecording = null; - [SerializeField] - private GameObject buttonStartPlaybackInactive = null; - + [Tooltip("Root GameObject that allows the user to start playback of a log file")] [SerializeField] private GameObject buttonStartPlayback = null; + [Tooltip("Root GameObject that allows the user to pause a recording")] [SerializeField] private GameObject buttonPausePlayback = null; - public void Start() + [Tooltip("Root GameObject that allows the user to resume a recording")] + [SerializeField] + private GameObject buttonResumePlayback = null; + + private void Start() { RecordingUI_Reset(true); - ReplayUI_SetActive(false); + ShowStartButton(); } #region Data recording + /// + /// Updates the control UI when the user starts recording a new eye gaze log file. + /// public void StartRecording() { RecordingUI_Reset(false); } + /// + /// Updates the control UI when the user finishes recording a new eye gaze log file. + /// public void StopRecording() { RecordingUI_Reset(true); @@ -55,43 +69,56 @@ private void RecordingUI_Reset(bool reset) #endregion #region Data replay - public void LoadData() + /// + /// Updates the control UI with the initial state, and when the user completes playback of a eye gaze log file. + /// + public void ShowStartButton() { - ReplayUI_SetActive(true); - } - - private void ReplayUI_SetActive(bool active) - { - ResetPlayback(active, false); - - if (buttonStartPlaybackInactive != null) - { - buttonStartPlaybackInactive.SetActive(!active); - } + SetPlaybackButtons(true, false, false); } + /// + /// Updates the control UI when the user starts playback of a eye gaze log file. + /// public void StartReplay() { Debug.Log("StartReplay"); - ResetPlayback(false, true); + SetPlaybackButtons(false, true, false); } + /// + /// Updates the control UI when the user pauses playback of a eye gaze log file. + /// public void PauseReplay() { Debug.Log("PauseReplay"); - ResetPlayback(true, false); + SetPlaybackButtons(false, false, true); } - private void ResetPlayback(bool showPlayBtn, bool showPauseBtn) + /// + /// Updates the control UI when the user resumes playback of a eye gaze log file. + /// + public void ResumeReplay() + { + Debug.Log("ResumePlayback"); + SetPlaybackButtons(false, true, false); + } + + private void SetPlaybackButtons(bool showStartButton, bool showPauseButton, bool showResumeButton) { if (buttonStartPlayback != null) { - buttonStartPlayback.SetActive(showPlayBtn); + buttonStartPlayback.SetActive(showStartButton); } if (buttonPausePlayback != null) { - buttonPausePlayback.SetActive(showPauseBtn); + buttonPausePlayback.SetActive(showPauseButton); + } + + if (buttonResumePlayback != null) + { + buttonResumePlayback.SetActive(showResumeButton); } } #endregion From 5674ba043962676b044ee1cb7659cdb5211e5f22 Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Tue, 4 Jul 2023 19:17:29 -0300 Subject: [PATCH 6/9] - Rename EyeTrackingTarget variables to lower camel cases - Remove unreferenced function - Add documentation - Fix audio source references for object selection and deselection in Target Positioning scene - Update function visibility --- .../EyeTrackingCursor.prefab | 8 ++-- .../EyeTrackingExample-01-BasicSetup.unity | 38 +--------------- ...TrackingExample-04-TargetPositioning.unity | 36 +++++++-------- .../Scripts/EyeTracking/FollowEyeGaze.cs | 18 ++++---- .../TargetPositioning/MoveObjectByEyeGaze.cs | 44 ++++++++++--------- .../TargetPositioning/ObjectGoalZone.cs | 2 +- .../TargetSelectionDemo/EyeTrackingTarget.cs | 9 ++++ .../TargetSelectionDemo/FaceUser.cs | 3 +- .../TargetGroupCreatorRadial.cs | 11 ----- 9 files changed, 66 insertions(+), 103 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/EyeTrackingCursor.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/EyeTrackingCursor.prefab index addb9d11bff..76e107b8ecd 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/EyeTrackingCursor.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/EyeTrackingCursor.prefab @@ -283,10 +283,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f794cd1785a414045977779c0ff5bd79, type: 3} m_Name: m_EditorClassIdentifier: - _defaultDistanceInMeters: 2 - _idleStateColor: {r: 0.94482756, g: 0, b: 1, a: 0.5019608} - _hightlightStateColor: {r: 0.61972624, g: 0.8897059, b: 0, a: 0.5019608} - _gazeController: {fileID: 0} + defaultDistanceInMeters: 2 + idleStateColor: {r: 0.94482756, g: 0, b: 1, a: 0.5019608} + hightlightStateColor: {r: 0.61972624, g: 0.8897059, b: 0, a: 0.5019608} + gazeController: {fileID: 0} _gazeTranslationAction: m_UseReference: 0 m_Action: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity index decaeb75e4c..bfd072fb376 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity @@ -2131,10 +2131,6 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 0} m_Modifications: - - target: {fileID: 4583486472360274399, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - target: {fileID: 4661674953859262252, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} propertyPath: m_RootOrder value: 6 @@ -2184,41 +2180,9 @@ PrefabInstance: value: EyeTracking_Cursor objectReference: {fileID: 0} - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: m_Enabled - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _gazeController + propertyPath: gazeController value: objectReference: {fileID: 1530487695} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _idleStateColor.a - value: 0.5019608 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _idleStateColor.b - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _idleStateColor.r - value: 0.94482756 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _hightlightStateColor.a - value: 0.5019608 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _hightlightStateColor.g - value: 0.8897059 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _hightlightStateColor.r - value: 0.61972624 - objectReference: {fileID: 0} - - target: {fileID: 8364151238423769580, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} - propertyPath: _gazeTranslationAction.m_UseReference - value: 0 - objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} --- !u!114 &1152038354 stripped diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-04-TargetPositioning.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-04-TargetPositioning.unity index 0e126959a0f..5a05e1da861 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-04-TargetPositioning.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-04-TargetPositioning.unity @@ -337,7 +337,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -352,7 +352,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -595,10 +595,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: @@ -998,7 +998,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -1013,7 +1013,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -1256,10 +1256,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: @@ -13754,7 +13754,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -13769,7 +13769,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -14012,10 +14012,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: @@ -14774,7 +14774,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -14789,7 +14789,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -15032,10 +15032,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: @@ -36113,7 +36113,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -36128,7 +36128,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -36371,10 +36371,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: @@ -37081,7 +37081,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 175539ba68a64b84bbf06fa4460fb573, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 1cd58df2ed177f74cb6a1882c7e52079, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -37096,7 +37096,7 @@ MonoBehaviour: m_MethodName: PlayOneShot m_Mode: 2 m_Arguments: - m_ObjectArgument: {fileID: 8300000, guid: 8944f7f2ae6803b4eb94f98205dc5de0, type: 3} + m_ObjectArgument: {fileID: 8300000, guid: 49bfc3418fff4924886a8b52a7569152, type: 3} m_ObjectArgumentAssemblyTypeName: UnityEngine.AudioClip, UnityEngine m_IntArgument: 0 m_FloatArgument: 0 @@ -37339,10 +37339,10 @@ MonoBehaviour: freezeX: 0 freezeY: 0 freezeZ: 0 + placementSurface: 0 LocalMinMaxX: {x: -Infinity, y: Infinity} LocalMinMaxY: {x: -Infinity, y: Infinity} LocalMinMaxZ: {x: -Infinity, y: Infinity} - PlacementSurface: 0 onDrop: m_PersistentCalls: m_Calls: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs index f6587078248..ba0156cb1b9 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/FollowEyeGaze.cs @@ -12,27 +12,27 @@ namespace Microsoft.MixedReality.Toolkit.Examples { /// /// Sample for allowing the game object that this script is attached to follow the user's eye gaze - /// at a given distance of "DefaultDistanceInMeters". + /// at a given distance of . /// [AddComponentMenu("Scripts/MRTK/Examples/FollowEyeGaze")] public class FollowEyeGaze : MonoBehaviour { [Tooltip("Display the game object along the eye gaze ray at a default distance (in meters).")] [SerializeField] - private float _defaultDistanceInMeters = 2f; + private float defaultDistanceInMeters = 2f; [Tooltip("The default color of the GameObject.")] [SerializeField] - private Color _idleStateColor; + private Color idleStateColor; [Tooltip("The highlight color of the GameObject when hovered over another StatefulInteractable.")] [SerializeField] - private Color _hightlightStateColor; + private Color hightlightStateColor; private Material material; [SerializeField] - private ActionBasedController _gazeController; + private ActionBasedController gazeController; [SerializeField] private InputActionProperty _gazeTranslationAction; @@ -44,7 +44,7 @@ private void Awake() { material = GetComponent().material; - gazeInteractor = _gazeController.GetComponentInChildren(); + gazeInteractor = gazeController.GetComponentInChildren(); targets = new List(); } @@ -76,12 +76,12 @@ private void Update() targets.Clear(); gazeInteractor.GetValidTargets(targets); - material.color = targets.Count > 0 ? _hightlightStateColor : _idleStateColor; + material.color = targets.Count > 0 ? hightlightStateColor : idleStateColor; // Note: A better workflow would be to create and attach a prefab to the MRTK Gaze Controller object. // Doing this will parent the cursor to the gaze controller transform and be updated automatically. - var pose = _gazeController.transform.GetWorldPose(); - transform.position = pose.position + _gazeController.transform.forward * _defaultDistanceInMeters; + var pose = gazeController.transform.GetWorldPose(); + transform.position = pose.position + gazeController.transform.forward * defaultDistanceInMeters; } private void FollowEyeGazeAction(InputAction.CallbackContext obj) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs index 63ca2c01353..c6085410585 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/MoveObjectByEyeGaze.cs @@ -157,7 +157,6 @@ private bool // The values represents the minimal angle that the surface must be offset from the 'up' vector to be considered for vertical placement. private readonly float minDiffAngleForVerticalPlacement = 50f; - #endregion public override float Selectedness() @@ -165,6 +164,10 @@ public override float Selectedness() return objectIsGrabbed ? 1f : base.Selectedness(); } + /// + /// Moves the GameObject while it is grabbed using hand interactors if enabled, and places a preview object at the eye gaze + /// position if eye gaze interaction is enabled. + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { // Dynamic is effectively just your normal Update(). @@ -277,11 +280,17 @@ public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase up } #region Hand input handler + /// + /// Called when a user selects the GameObject using a hand based interactor. + /// public void OnGrabSelectedEntered() { HandDrag_Start(); } + /// + /// Called when a user deselects the GameObject using a hand based interactor. + /// public void OnGrabSelectedExited() { HandDrag_Stop(); @@ -289,12 +298,18 @@ public void OnGrabSelectedExited() #endregion #region Voice input handler + /// + /// Called when a user selects the GameObject using a voice based interactor + /// public void OnVoiceSelectedEntered() { isManipulatingUsingVoice = true; DragAndDrop_Start(); } + /// + /// Called when a user deselects the GameObject using a voice based interactor + /// public void OnVoiceSelectedExited() { DragAndDrop_Finish(); @@ -456,7 +471,7 @@ private void DeactivatePreview() /// /// Begin with the selection and movement of the focused target. /// - public void DragAndDrop_Start() + private void DragAndDrop_Start() { if (!objectIsGrabbed && isHovered) { @@ -479,7 +494,7 @@ public void DragAndDrop_Start() /// /// Finalize placing the currently selected target. /// - public void DragAndDrop_Finish() + private void DragAndDrop_Finish() { if (objectIsGrabbed) { @@ -519,7 +534,7 @@ private void RelativeMoveUpdate(Vector3 relativeMovement) /// /// Compute the angle between the initial (when selecting the target) and current eye gaze direction. /// - public float Angle_InitialGazeToCurrGazeDir() + private float Angle_InitialGazeToCurrGazeDir() { return Vector3.Angle(initalGazeDirection, Camera.main.transform.forward); } @@ -527,7 +542,7 @@ public float Angle_InitialGazeToCurrGazeDir() /// /// Compute angle between target center ( OR original targeting location??? ) and current targeting direction /// - public float Angle_ToCurrHitTarget(GameObject gobj) + private float Angle_ToCurrHitTarget(GameObject gobj) { if (gazeInteractor.PreciseHitResult.targetInteractable != null) { @@ -570,7 +585,7 @@ private bool HeadIsInMotion() return headIsInMotion; } - public void MoveTargetBy(Vector3 delta) + private void MoveTargetBy(Vector3 delta) { // Check that this game object is currently selected if (objectIsGrabbed) @@ -621,7 +636,7 @@ public void MoveTargetBy(Vector3 delta) } } - public void ConstrainMovement() + private void ConstrainMovement() { Vector3 locPos = gameObject.transform.localPosition; float rx = Mathf.Clamp(locPos.x, LocalMinMaxX.x, LocalMinMaxX.y); @@ -631,20 +646,7 @@ public void ConstrainMovement() gameObject.transform.localPosition = new Vector3(rx, ry, rz); } - /*public void OnDrop_SnapToClosestDecimal() - { - if (_sliderSnapToNearestDecimal != 0f - && !float.IsPositiveInfinity(LocalMinMaxX.x) && !float.IsNegativeInfinity(LocalMinMaxX.x) - && !float.IsPositiveInfinity(LocalMinMaxX.y) && !float.IsNegativeInfinity(LocalMinMaxX.y)) - { - Vector3 locPos = gameObject.transform.localPosition; - float normalizedValue = (locPos.x - LocalMinMaxX.x) / (LocalMinMaxX.y - LocalMinMaxX.x); - locPos.x = (Mathf.Round(normalizedValue / _sliderSnapToNearestDecimal) * _sliderSnapToNearestDecimal) * (LocalMinMaxX.y - LocalMinMaxX.x) + LocalMinMaxX.x; - gameObject.transform.localPosition = locPos; - } - }*/ - - public void MoveTargetTo(Vector3 destination) + private void MoveTargetTo(Vector3 destination) { // Check that this game object is currently selected if (objectIsGrabbed) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs index 07b1d201bf4..63780e2591d 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetPositioning/ObjectGoalZone.cs @@ -63,7 +63,7 @@ private void OnTriggerEnter(Collider other) /// /// If an already enrolled collider leaves our trigger zone, let's remove it from the list of currently colliding targets. /// - void OnTriggerExit(Collider other) + private void OnTriggerExit(Collider other) { if (currentCollidingObjects.Contains(other.gameObject.name)) { diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs index a174433f72b..b213a4b8df5 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/EyeTrackingTarget.cs @@ -58,16 +58,25 @@ private void Awake() interactable = GetComponent(); } + /// + /// Called when a user begins a hover on the GameObject using a gaze based interactor. + /// public void OnGazeHoverEntered() { rotationCoroutine = StartCoroutine(RotateTarget()); } + /// + /// Called when a user leaves a hover on the GameObject using a gaze based interactor. + /// public void OnGazeHoverExited() { StopCoroutine(rotationCoroutine); } + /// + /// Called when a user selects the GameObject. + /// public void OnTargetSelected() { if (!interactable.isHovered) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs index fabcb069824..b2ba6fd9df7 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/FaceUser.cs @@ -84,8 +84,7 @@ private void InitialSetup() originalForwardNormalized = targetToRotate.transform.forward.normalized; } - // Update is called once per frame - public void Update() + private void Update() { // Update target rotation Vector3 TargetToCamera = (Camera.main.transform.position - targetToRotate.transform.position).normalized; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs index b6773011629..e15dfbd2c3a 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/TargetSelectionDemo/TargetGroupCreatorRadial.cs @@ -118,17 +118,6 @@ private void CreateNewTargets_RadialLayout() } } - /// - /// List of all instantiated targets. - /// - internal GameObject[] InstantiatedObjects - { - get - { - return instantiatedTargets?.ToArray(); - } - } - /// /// Returns a random template. /// From 90811f6516ecb1e6e102b964ba6c3c04ac233fbf Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Wed, 5 Jul 2023 13:11:11 -0300 Subject: [PATCH 7/9] - Fix properties for eye tracking targets in target selection scene - Add DisableOnStart script for dialog that needed to be disabled at runtime - Add documentation for PanZoom StatefulInteractables --- .../EyeTracking_BlueTarget.prefab | 10 +-- .../EyeTracking_GreenTarget.prefab | 10 +-- .../EyeTracking_PurpleTarget.prefab | 10 +-- .../EyeTracking_YellowTarget.prefab | 10 +-- .../EyeTrackingExample-01-BasicSetup.unity | 17 ----- ...yeTrackingExample-02-TargetSelection.unity | 8 ++- .../Scripts/EyeTracking/DisableOnStart.cs | 19 ++++++ .../EyeTracking/DisableOnStart.cs.meta | 11 +++ .../EyeTracking/ScrollPanZoom/PanZoomBase.cs | 68 ++++++++++++++++--- .../ScrollPanZoom/PanZoomBaseRectTransform.cs | 22 +++--- .../ScrollPanZoom/PanZoomBaseTexture.cs | 21 +++--- .../ScrollPanZoom/PanZoomTexture.cs | 1 + .../ScrollPanZoom/ScrollRectTransform.cs | 1 + 13 files changed, 142 insertions(+), 66 deletions(-) create mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs create mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs.meta diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_BlueTarget.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_BlueTarget.prefab index 098484d72ff..fe4255a1c87 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_BlueTarget.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_BlueTarget.prefab @@ -5137,7 +5137,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 4091664850906067337} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverEntered m_Mode: 1 @@ -5153,7 +5153,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 4091664850906067337} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverExited m_Mode: 1 @@ -5256,7 +5256,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 4091664850906067337} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnTargetSelected m_Mode: 1 @@ -5290,8 +5290,8 @@ MonoBehaviour: audioFxCorrectTarget: {fileID: 8300000, guid: 50b629cc6a6feb0458f4b22b5c96eb91, type: 3} audioFxIncorrectTarget: {fileID: 8300000, guid: ca1d2149dae1f1c46bd86eda5ac11494, type: 3} isValidTarget: 1 - rotateByEulerAngles: {x: 0, y: 0, z: 0} - speed: 1 + rotateByEulerAngles: {x: 0, y: 1, z: 1} + speed: 0.5 --- !u!114 &4629736370831257364 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_GreenTarget.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_GreenTarget.prefab index ca81190cf03..a08027246bf 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_GreenTarget.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_GreenTarget.prefab @@ -325,7 +325,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5482834646519813981} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverEntered m_Mode: 1 @@ -341,7 +341,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5482834646519813981} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverExited m_Mode: 1 @@ -444,7 +444,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5482834646519813981} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnTargetSelected m_Mode: 1 @@ -478,8 +478,8 @@ MonoBehaviour: audioFxCorrectTarget: {fileID: 8300000, guid: 50b629cc6a6feb0458f4b22b5c96eb91, type: 3} audioFxIncorrectTarget: {fileID: 8300000, guid: ca1d2149dae1f1c46bd86eda5ac11494, type: 3} isValidTarget: 1 - rotateByEulerAngles: {x: 0, y: 0, z: 0} - speed: 1 + rotateByEulerAngles: {x: 0, y: 1, z: 1} + speed: 0.5 --- !u!114 &8289819128855617247 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_PurpleTarget.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_PurpleTarget.prefab index 691d402b275..84b5295040d 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_PurpleTarget.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_PurpleTarget.prefab @@ -5137,7 +5137,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 920865073573836204} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverEntered m_Mode: 1 @@ -5153,7 +5153,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 920865073573836204} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverExited m_Mode: 1 @@ -5256,7 +5256,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 920865073573836204} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnTargetSelected m_Mode: 1 @@ -5290,8 +5290,8 @@ MonoBehaviour: audioFxCorrectTarget: {fileID: 8300000, guid: 50b629cc6a6feb0458f4b22b5c96eb91, type: 3} audioFxIncorrectTarget: {fileID: 8300000, guid: ca1d2149dae1f1c46bd86eda5ac11494, type: 3} isValidTarget: 1 - rotateByEulerAngles: {x: 0, y: 0, z: 0} - speed: 1 + rotateByEulerAngles: {x: 0, y: 1, z: 1} + speed: 0.5 --- !u!114 &8270335104292374827 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_YellowTarget.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_YellowTarget.prefab index 2daaad77a37..54cb89ca15b 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_YellowTarget.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/TargetSelection/EyeTracking_YellowTarget.prefab @@ -5137,7 +5137,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5857853439839890309} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverEntered m_Mode: 1 @@ -5153,7 +5153,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5857853439839890309} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnGazeHoverExited m_Mode: 1 @@ -5256,7 +5256,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 5857853439839890309} - m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking.EyeTrackingTarget, + m_TargetAssemblyTypeName: Microsoft.MixedReality.Toolkit.Examples.EyeTrackingTarget, Assembly-CSharp m_MethodName: OnTargetSelected m_Mode: 1 @@ -5290,8 +5290,8 @@ MonoBehaviour: audioFxCorrectTarget: {fileID: 8300000, guid: 50b629cc6a6feb0458f4b22b5c96eb91, type: 3} audioFxIncorrectTarget: {fileID: 8300000, guid: ca1d2149dae1f1c46bd86eda5ac11494, type: 3} isValidTarget: 1 - rotateByEulerAngles: {x: 0, y: 0, z: 0} - speed: 1 + rotateByEulerAngles: {x: 0, y: 1, z: 1} + speed: 0.5 --- !u!114 &8278177351404225702 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity index bfd072fb376..6a8f1077b83 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-01-BasicSetup.unity @@ -1207,23 +1207,6 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 3220012215463627515, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} m_PrefabInstance: {fileID: 857220365} m_PrefabAsset: {fileID: 0} ---- !u!1 &857220367 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 6540126486176102408, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} - m_PrefabInstance: {fileID: 857220365} - m_PrefabAsset: {fileID: 0} ---- !u!114 &857220368 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 857220367} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36eae551b67b6d74da769f7ceb8c1fe7, type: 3} - m_Name: - m_EditorClassIdentifier: --- !u!4 &890841641 stripped Transform: m_CorrespondingSourceObject: {fileID: 4661674953859262252, guid: c9d9edba85c2c504c962d7cd830d9e3e, type: 3} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-02-TargetSelection.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-02-TargetSelection.unity index 702550f98f3..846415d8a4f 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-02-TargetSelection.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-02-TargetSelection.unity @@ -455,6 +455,10 @@ PrefabInstance: propertyPath: m_Name value: Infotext_GazeAndCommit objectReference: {fileID: 0} + - target: {fileID: 6540126486176102408, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} - target: {fileID: 6809291684801504143, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} propertyPath: m_text value: @@ -471,7 +475,7 @@ GameObject: m_CorrespondingSourceObject: {fileID: 6540126486176102408, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} m_PrefabInstance: {fileID: 300645523} m_PrefabAsset: {fileID: 0} ---- !u!114 &300645526 +--- !u!114 &300645529 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -480,7 +484,7 @@ MonoBehaviour: m_GameObject: {fileID: 300645525} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36eae551b67b6d74da769f7ceb8c1fe7, type: 3} + m_Script: {fileID: 11500000, guid: a7212b095e2da2c4cbb76f18506096c7, type: 3} m_Name: m_EditorClassIdentifier: --- !u!1 &341941212 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs new file mode 100644 index 00000000000..6b227a6938a --- /dev/null +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using UnityEngine; + +namespace Microsoft.MixedReality.Toolkit.Examples +{ + /// + /// Simple class that automatically hides a target on startup. This is, for example, useful for nested canvas object. + /// + [AddComponentMenu("Scripts/MRTK/Examples/DisableOnStart")] + public class DisableOnStart : MonoBehaviour + { + private void Awake() + { + gameObject.SetActive(false); + } + } +} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs.meta b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs.meta new file mode 100644 index 00000000000..7e11c1122aa --- /dev/null +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/DisableOnStart.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7212b095e2da2c4cbb76f18506096c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBase.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBase.cs index 7214365ff7f..85abb80c4c5 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBase.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBase.cs @@ -119,13 +119,40 @@ public abstract class PanZoomBase : StatefulInteractable protected Vector2 originalScale; #endregion - public abstract void Initialize(); - public abstract float ComputePanSpeed(float cursorPosInOneDir, float maxSpeed, float minDistFromCenterForAutoPan); - public abstract int ZoomDir(bool zoomIn); - public abstract void ZoomIn(); - public abstract void ZoomOut(); - public abstract void UpdatePanZoom(); - public abstract bool UpdateCursorPosInHitBox(Vector3 hitPosition); + /// + /// Initializes the state of the interactable. + /// + protected abstract void Initialize(); + + /// + /// Computes the pan speed based on the distance from interactor position to the center of the interactable. + /// + protected abstract float ComputePanSpeed(float cursorPosInOneDir, float maxSpeed, float minDistFromCenterForAutoPan); + + /// + /// Determines the sign of the zoom direction for zooming in and out. + /// + protected abstract int ZoomDir(bool zoomIn); + + /// + /// Zooms in the GameObject. + /// + protected abstract void ZoomIn(); + + /// + /// Zooms out the GameObject. + /// + protected abstract void ZoomOut(); + + /// + /// + /// + protected abstract void UpdatePanZoom(); + + /// + /// Determine the position of the cursor within the hitbox. + /// + protected abstract bool UpdateCursorPosInHitBox(Vector3 hitPosition); protected virtual void Start() { @@ -143,7 +170,7 @@ private Vector3 CustomColliderSizeOnLookAt } } - public void AutoPan() + protected void AutoPan() { PanHorizontally(ComputePanSpeed(cursorPosition.x, panSpeedLeftRight, minDistFromCenterForAutoPan.x)); PanVertically(ComputePanSpeed(cursorPosition.y, panSpeedUpDown, minDistFromCenterForAutoPan.y)); @@ -165,11 +192,17 @@ public void PanVertically(float speed) offsetRatePan = new Vector2(offsetRatePan.x, Time.deltaTime * speed); } + /// + /// Enables zoom operations using hand based interators. + /// public void EnableHandZoom() { handZoomEnabled = true; } + /// + /// Disables zoom operations using hand based interators. + /// public void DisableHandZoom() { handZoomEnabled = false; @@ -184,13 +217,13 @@ private void ZoomStart(bool zoomIn) zoomDirection = ZoomDir(zoomIn); } - public void ZoomInStart() + private void ZoomInStart() { Debug.Log($"[{gameObject.name}] ZoomInStart: {scale}"); ZoomStart(true); } - public void ZoomOutStart() + private void ZoomOutStart() { Debug.Log($"[{gameObject.name}] ZoomOutStart: {scale}"); ZoomStart(false); @@ -258,6 +291,7 @@ private void NavigationUpdate(Vector3 normalizedOffset) private Vector3 initialPalmPosition; private XRNode handUsedToZoom; + [Tooltip("Toggles the direction of hand based zoom interactions")] [SerializeField] private bool invertPalmZoomDirection = true; @@ -365,7 +399,7 @@ internal void SetSkimProofUpdateSpeed(float newSpeed) skimproof_UpdateSpeed = newSpeed / 1000f; } - public void ResetNormFixator() + protected void ResetNormFixator() { skimProofNormalFixator = 0f; } @@ -483,11 +517,17 @@ protected Vector2 LimitScaling(Vector2 newScale) return newScale; } + /// + /// Begins a zoom in operation on the GameObject. + /// public void ZoomIn_Timed() { StartCoroutine(ZoomAndStop(true)); } + /// + /// Begins a zoom out operation on the GameObject. + /// public void ZoomOut_Timed() { StartCoroutine(ZoomAndStop(false)); @@ -528,11 +568,17 @@ internal bool UpdateValues(ref T objBase, T objLocal) } #region Handle input events + /// + /// Called when a user selects the GameObject. + /// public void OnSelectEntered() { IsZooming = true; } + /// + /// Called when a user deselects the GameObject. + /// public void OnSelectExited() { // Stop zoom diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseRectTransform.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseRectTransform.cs index 1a18ba38f24..fbdca0bd481 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseRectTransform.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseRectTransform.cs @@ -17,8 +17,9 @@ public class PanZoomBaseRectTransform : PanZoomBase internal bool isScrollText = false; private bool IsValid => navigationRectTransform != null; - - public override void Initialize() + + /// + protected override void Initialize() { if (IsValid) { @@ -29,7 +30,8 @@ public override void Initialize() } } - public override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float minDistFromCenterForAutoPan) + /// + protected override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float minDistFromCenterForAutoPan) { // UV space from [0,1] -> Center: [-0.5, 0.5] float centeredVal = uvCursorPos - 0.5f; @@ -45,12 +47,14 @@ public override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float m return speed; } - public override int ZoomDir(bool zoomIn) + /// + protected override int ZoomDir(bool zoomIn) { return zoomIn ? 1 : -1; } - public override void ZoomIn() + /// + protected override void ZoomIn() { ZoomInOut_RectTransform(zoomDirection * zoomSpeed, cursorPosition); @@ -59,12 +63,14 @@ public override void ZoomIn() PanVertically(ComputePanSpeed(cursorPosition.y, panSpeedUpDown, minDistFromCenterForAutoPan.y)); } - public override void ZoomOut() + /// + protected override void ZoomOut() { ZoomInOut_RectTransform(zoomDirection * zoomSpeed, new Vector2(0.5f, 0.5f)); } - public override void UpdatePanZoom() + /// + protected override void UpdatePanZoom() { offset = LimitPanning(); @@ -161,7 +167,7 @@ private void ZoomInOut_RectTransform(float speed, Vector2 pivot) /// Determine the position of the cursor within the hitbox. /// /// True if this GameObject is hit. - public override bool UpdateCursorPosInHitBox(Vector3 hitPosition) + protected override bool UpdateCursorPosInHitBox(Vector3 hitPosition) { Vector3 center = gameObject.transform.position; Vector3 halfsize = gameObject.transform.lossyScale * 0.5f; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseTexture.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseTexture.cs index b5aefbc96f2..15b7f181b30 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseTexture.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomBaseTexture.cs @@ -35,7 +35,8 @@ public string TextureShaderProperty private bool IsValid => (textureRenderer != null) && textureRenderer.enabled; - public override void Initialize() + /// + protected override void Initialize() { if (aspectRatio == -1f) { @@ -47,7 +48,7 @@ public override void Initialize() } } - public void Initialize(float newAspectRatio) + private void Initialize(float newAspectRatio) { if (IsValid && aspectRatio != 0f) { @@ -73,7 +74,7 @@ public void Initialize(float newAspectRatio) /// Returns the pan speed. /// /// Normalized cursor position in the hit box. Center is assumed to be at [-0.5, 0.5]. - public override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float minDistFromCenterForAutoPan) + protected override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float minDistFromCenterForAutoPan) { // UV space from [0,1] -> Center: [-0.5, 0.5] float centeredVal = uvCursorPos - 0.5f; @@ -91,7 +92,8 @@ public override float ComputePanSpeed(float uvCursorPos, float maxSpeed, float m } } - public override void UpdatePanZoom() + /// + protected override void UpdatePanZoom() { if (IsValid) { @@ -127,12 +129,14 @@ public override void UpdatePanZoom() } } - public override int ZoomDir(bool zoomIn) + /// + protected override int ZoomDir(bool zoomIn) { return zoomIn ? -1 : 1; } - public override void ZoomIn() + /// + protected override void ZoomIn() { if (IsZooming) { @@ -144,7 +148,8 @@ public override void ZoomIn() } } - public override void ZoomOut() + /// + protected override void ZoomOut() { if (IsZooming) { @@ -175,7 +180,7 @@ private void ZoomInOut(float speed, Vector2 pivot) /// Determine the position of the cursor within the texture in UV space. /// /// True if this GameObject is hit. - public override bool UpdateCursorPosInHitBox(Vector3 hitPosition) + protected override bool UpdateCursorPosInHitBox(Vector3 hitPosition) { Vector3 center = gameObject.transform.position; Vector3 halfsize = gameObject.transform.lossyScale * 0.5f; diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomTexture.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomTexture.cs index 17bf0260e85..7ae2cd7d773 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomTexture.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/PanZoomTexture.cs @@ -88,6 +88,7 @@ protected override void Start() base.Start(); } + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { base.ProcessInteractable(updatePhase); diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/ScrollRectTransform.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/ScrollRectTransform.cs index 311647ade00..a55fd33b422 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/ScrollRectTransform.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/ScrollPanZoom/ScrollRectTransform.cs @@ -80,6 +80,7 @@ private void UpdatePivot() navigationRectTransform.anchorMax = new Vector2(0f, 1f); } + /// public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { base.ProcessInteractable(updatePhase); From a8e799b99cec78d71052ab62d2d57fb814c04867 Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Thu, 6 Jul 2023 10:45:12 -0300 Subject: [PATCH 8/9] - Fix UserInputPlayback in UWP - Removed creation of a subfolder in FileInputLogger - Note: MusicLibrary permission needs to be granted in PlayerSettings --- .../Visualizer/Controls.prefab | 9 +- .../EyeTrackingExample-05-Visualizer.unity | 10 +- .../EyeTracking/Visualizer/FileInputLogger.cs | 118 +++++---------- .../Visualizer/UserInputPlayback.cs | 140 +++++++++--------- .../Visualizer/UserInputRecorder.cs | 6 +- 5 files changed, 111 insertions(+), 172 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab index bd13b428859..ece7a6333dc 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab +++ b/UnityProjects/MRTKDevTemplate/Assets/Prefabs/EyeTrackingExamples/Visualizer/Controls.prefab @@ -975,7 +975,7 @@ MonoBehaviour: buttonStopRecording: {fileID: 6802997350238223167} buttonStartPlayback: {fileID: 8310050747605233910} buttonPausePlayback: {fileID: 191985091076322603} - buttonResumePlayback: {fileID: 8237818353018430703} + buttonResumePlayback: {fileID: 715919861} --- !u!114 &2087141182152323438 MonoBehaviour: m_ObjectHideFlags: 0 @@ -988,7 +988,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 7a97caac99350c446a783a1bc3e9bf1e, type: 3} m_Name: m_EditorClassIdentifier: - filenameToUse: test + filenameToUse: mrtk_log_mostRecentET addTimestampToLogfileName: 0 logStructure: {fileID: 9111033687875367441} userName: tester @@ -2539,8 +2539,3 @@ Transform: m_CorrespondingSourceObject: {fileID: 2244185731585867246, guid: cd0f0697f0939504389ec612388f609a, type: 3} m_PrefabInstance: {fileID: 7887614037859475424} m_PrefabAsset: {fileID: 0} ---- !u!1 &8237818353018430703 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 2244185731031694095, guid: cd0f0697f0939504389ec612388f609a, type: 3} - m_PrefabInstance: {fileID: 7887614037859475424} - m_PrefabAsset: {fileID: 0} diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity index 7fd5f97e322..721bc06fe2c 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeTracking/EyeTrackingExample-05-Visualizer.unity @@ -703,11 +703,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &715919861 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 715919861, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - m_PrefabInstance: {fileID: 7887614037481751899} - m_PrefabAsset: {fileID: 0} --- !u!1 &870610048 GameObject: m_ObjectHideFlags: 0 @@ -1180,6 +1175,7 @@ MonoBehaviour: m_StringArgument: m_BoolArgument: 0 m_CallState: 2 + UserNameFolder: tester --- !u!224 &1261404671 stripped RectTransform: m_CorrespondingSourceObject: {fileID: 3220012215463627515, guid: e8c3ea3c1046f8b4bbd682c2b7a0e4fe, type: 3} @@ -2030,10 +2026,6 @@ PrefabInstance: propertyPath: k__BackingField.m_PersistentCalls.m_Calls.Array.data[1].m_Target value: objectReference: {fileID: 1232406737} - - target: {fileID: 5685716680725385779, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} - propertyPath: buttonResumePlayback - value: - objectReference: {fileID: 715919861} - target: {fileID: 5853303421825090637, guid: 0745c2d3ca133584e996e8cd69f6d0aa, type: 3} propertyPath: m_RootOrder value: 2 diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs index 4ced5129222..4070db84fe1 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/FileInputLogger.cs @@ -6,6 +6,7 @@ using UnityEngine; #if WINDOWS_UWP +using System.Text; using Windows.Storage; #endif @@ -17,17 +18,19 @@ namespace Microsoft.MixedReality.Toolkit.Examples public class FileInputLogger : IDisposable { private bool disposed = false; - private StreamWriter logFile = null; + private StreamWriter logFileStream = null; - public FileInputLogger(string userNameFolder, string fileName) + public FileInputLogger(string fileName) { - UserNameFolder = userNameFolder; - + Filename = fileName; + #if WINDOWS_UWP - await CreateNewLogFile(); + CreateNewLogFile(); + buffer = new StringBuilder(); #else - logFile = File.CreateText(Application.persistentDataPath + "/" + fileName); - logFile.AutoFlush = true; + Debug.Log(Application.persistentDataPath + "/" + fileName); + logFileStream = File.CreateText(Application.persistentDataPath + "/" + fileName); + logFileStream.AutoFlush = true; #endif } @@ -40,71 +43,55 @@ public void Dispose() { return; } - disposed = true; - - logFile.Close(); - logFile.Dispose(); + +#if !WINDOWS_UWP + logFileStream.Close(); + logFileStream.Dispose(); +#endif } - /// - /// A user folder to store logs file in UWP - /// - private string UserNameFolder { get; set; } + private string Filename { get; } #if WINDOWS_UWP - public string LogDirectory => "MRTK_ET_Demo/" + UserNameFolder; - private StorageFile logFile; - private StorageFolder logRootFolder = KnownFolders.MusicLibrary; - private StorageFolder sessionFolder; + + private StringBuilder buffer; protected virtual async void CreateNewLogFile() { try { - Debug.Log(">> BasicInputLogger.CreateNewLogFile: " + logRootFolder.ToString()); + StorageFolder logRootFolder = KnownFolders.MusicLibrary; + Debug.Log(">> FileInputLogger.CreateNewLogFile: " + logRootFolder.ToString()); if (logRootFolder != null) { - string fullPath = Path.Combine(logRootFolder.Path, LogDirectory); - Debug.LogFormat("Does directory already exist {0} --\nLogRootFolder: {2} \n {1}", Directory.Exists(fullPath), fullPath, logRootFolder.Path); - - try - { - if (!Directory.Exists(fullPath)) - { - Debug.LogFormat("Trying to create new directory.."); - Debug.LogFormat("Full path: " + fullPath); - sessionFolder = await logRootFolder.CreateFolderAsync(LogDirectory, CreationCollisionOption.GenerateUniqueName); - } - - sessionFolder = await logRootFolder.GetFolderAsync(LogDirectory); - logFile = await sessionFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting); - - Debug.Log(string.Format("*** Create log file to: {0} -- \n -- {1}", sessionFolder.Name, sessionFolder.Path)); + logFile = await logRootFolder.CreateFileAsync(Filename, CreationCollisionOption.ReplaceExisting); + Debug.Log(string.Format("*** The log file path is: {0} -- \n -- {1}", logFile.Name, logFile.Path)); - } - catch (FileNotFoundException) - { - sessionFolder = await logRootFolder.CreateFolderAsync(LogDirectory, CreationCollisionOption.GenerateUniqueName); - } - catch (DirectoryNotFoundException) { } - catch { } } } catch (Exception e) { - Debug.Log(string.Format("Exception in BasicLogger: {0}", e.Message)); + Debug.Log(string.Format("Exception in FileInputLogger: {0}", e.Message)); } } #endif -#region Append Log #if WINDOWS_UWP - public async void AppendLog(string message) + public void AppendLog(string message) { // Log buffer to the file - await FileIO.AppendTextAsync(logFile, message); + buffer.Append(message); + } + + public async void SaveLogs() + { + if (buffer.Length > 0) + { + // Log buffer to the file + await FileIO.AppendTextAsync(logFile, buffer.ToString()); + } } #else /// @@ -112,42 +99,7 @@ public async void AppendLog(string message) /// public void AppendLog(string message) { - logFile.Write(message); - } -#endif -#endregion - -#if WINDOWS_UWP - public async void LoadLogs() - { - try - { - if (logRootFolder != null) - { - string fullPath = Path.Combine(logRootFolder.Path, LogDirectory); - - try - { - if (!Directory.Exists(fullPath)) - { - return; - } - - sessionFolder = await logRootFolder.GetFolderAsync(LogDirectory); - logFile = await sessionFolder.GetFileAsync(filename); - } - catch (FileNotFoundException) - { - sessionFolder = await logRootFolder.CreateFolderAsync(LogDirectory, CreationCollisionOption.GenerateUniqueName); - } - catch (DirectoryNotFoundException) { } - catch (Exception) { } - } - } - catch (Exception e) - { - Debug.Log(string.Format("Exception in BasicLogger to load log file: {0}", e.Message)); - } + logFileStream.Write(message); } #endif } diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs index 5a12285f8ff..6645019134f 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputPlayback.cs @@ -7,6 +7,7 @@ using System.IO; using TMPro; using UnityEngine; +using UnityEngine.Events; #if WINDOWS_UWP using System.Threading.Tasks; @@ -15,8 +16,6 @@ namespace Microsoft.MixedReality.Toolkit.Examples { - using UnityEngine.Events; - /// /// Allows the user to playback a recorded log file of eye gaze interactions with a heat map. /// @@ -38,18 +37,10 @@ public class UserInputPlayback : MonoBehaviour [Tooltip("Event that is fired when playback of a log file has completed")] [SerializeField] private UnityEvent onPlaybackCompleted; - + private IReadOnlyList loggedLines; private Coroutine showHeatmapCoroutine; -#if WINDOWS_UWP - private StorageFolder uwpRootFolder = KnownFolders.MusicLibrary; - private readonly string uwpSubFolderName = $"MRTK_ET_Demo{Path.DirectorySeparatorChar}tester"; - private readonly string uwpFileName = "mrtk_log_mostRecentET.csv"; - private StorageFolder uwpLogSessionFolder; - private StorageFile uwpLogFile; -#endif - private void Start() { IsPlaying = false; @@ -69,62 +60,6 @@ private void ResetCurrentStream() loggedLines = null; } -#if WINDOWS_UWP - public async Task UWP_Load() - { - return await UWP_LoadNewFile(FileName); - } - - public async Task UWP_LoadNewFile(string filename) - { - ResetCurrentStream(); - bool fileExists = await UWP_FileExists(uwpSubFolderName, uwpFileName); - - if (fileExists) - { - loadingUpdateStatusText.text = "File exists: " + uwpFileName; - await UWP_ReadData(uwpLogFile); - } - else - { - loadingUpdateStatusText.text = "Error: File does not exist! " + uwpFileName; - return false; - } - - return true; - } - - public async Task UWP_FileExists(string dir, string filename) - { - try - { - uwpLogSessionFolder = await uwpRootFolder.GetFolderAsync(dir); - uwpLogFile = await uwpLogSessionFolder.GetFileAsync(filename); - - return true; - } - catch - { - loadingUpdateStatusText.text = "Error: File could not be found."; - } - - return false; - } - - private async Task UWP_ReadData(StorageFile logfile) - { - using var inputStream = await logfile.OpenReadAsync(); - using var classicStream = inputStream.AsStreamForRead(); - using var streamReader = new StreamReader(classicStream); - while (streamReader.Peek() >= 0) - { - loggedLines.Add(streamReader.ReadLine()); - } - loadingUpdateStatusText.text = "Finished loading log file. Lines: " + loggedLines.Count; - return true; - } -#endif - private bool IsDataLoaded { get { return loggedLines != null && loggedLines.Count > 0; } @@ -202,10 +137,67 @@ private void LoadInEditor() #if WINDOWS_UWP private async void LoadInUWP() { - loadingUpdateStatusText.text = "[Load.1] " + FileName; - await UWP_Load(); + loadingUpdateStatusText.text = "[LoadInUWP] " + FileName; + try + { + bool loaded = await LoadLogs(); + if (loaded) + { + await ReadData(); + } + else + { + Debug.Log("Could not load file."); + } + } + catch (Exception e) + { + Debug.Log(string.Format("Exception: {0}", e.Message)); + loadingUpdateStatusText.text = $"[LoadInUWP] File load failed: {e.Message}"; + } + } + + private StorageFile logFile; + public async Task LoadLogs() + { + try + { + StorageFolder logRootFolder = KnownFolders.MusicLibrary; + if (logRootFolder != null) + { + //string fullPath = Path.Combine(logRootFolder.Path, LogDirectory); + + //if (!Directory.Exists(fullPath)) + //{ + // return; + //} + + //sessionFolder = await logRootFolder.GetFolderAsync(LogDirectory); + logFile = await logRootFolder.GetFileAsync(playbackLogFilename); + return true; + } + } + catch (Exception e) + { + Debug.Log(string.Format("Exception in BasicLogger to load log file: {0}", e.Message)); + } + return false; + } + + public async Task ReadData() + { + var stream = await logFile.OpenAsync(Windows.Storage.FileAccessMode.Read); + using var inputStream = stream.GetInputStreamAt(0); + using var dataReader = new Windows.Storage.Streams.DataReader(inputStream); + uint numBytesLoaded = await dataReader.LoadAsync((uint)stream.Size); + string text = dataReader.ReadString(numBytesLoaded); + + loggedLines = text.Split(Environment.NewLine); + return true; } #endif + + /// /// True while the GameObject is playing back eye gaze data from the log file. /// @@ -228,7 +220,7 @@ private string FileName get { #if WINDOWS_UWP - return "C:\\Data\\Users\\DefaultAccount\\Music\\MRTK_ET_Demo\\tester\\" + playbackLogFilename; + return playbackLogFilename; #else return Application.persistentDataPath + "/" + playbackLogFilename; #endif @@ -247,8 +239,7 @@ private void ShowHeatmap() if (showHeatmapCoroutine != null) StopCoroutine(showHeatmapCoroutine); - - IsPlaying = true; + counter = 0; showHeatmapCoroutine = StartCoroutine(PopulateHeatmap()); } @@ -275,6 +266,11 @@ private IEnumerator PopulateHeatmap() { const float maxTargetingDistInMeters = 10f; +#if WINDOWS_UWP + yield return new WaitUntil(() => IsDataLoaded); +#endif + IsPlaying = true; + // Now let's populate the visualizer for (int i = 0; i < loggedLines.Count; i++) { diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs index 876293669ea..ebb7d53f6a7 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/EyeTracking/Visualizer/UserInputRecorder.cs @@ -41,13 +41,17 @@ public class UserInputRecorder : MonoBehaviour private void OnEnable() { - fileLogger = new FileInputLogger(userName, Filename); + fileLogger = new FileInputLogger(Filename); timerStart = DateTime.Now; fileLogger.AppendLog(GetHeader()); } private void OnDisable() { + #if WINDOWS_UWP + fileLogger.SaveLogs(); + #endif + fileLogger.Dispose(); fileLogger = null; } From f937cc2292e63385fcb6278a44e86e065e2dd149 Mon Sep 17 00:00:00 2001 From: Amelia Mesdag Date: Thu, 6 Jul 2023 12:23:42 -0300 Subject: [PATCH 9/9] Add missing meta file --- .../Assets/Scenes/EyeGazeExample.unity.meta | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeGazeExample.unity.meta diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeGazeExample.unity.meta b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeGazeExample.unity.meta new file mode 100644 index 00000000000..02f9b224ac1 --- /dev/null +++ b/UnityProjects/MRTKDevTemplate/Assets/Scenes/EyeGazeExample.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 34c7b3d86b487dd48818ba9904ee5c31 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: \ No newline at end of file