1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
+ using Microsoft . MixedReality . Toolkit . Input ;
4
5
using System ;
5
6
using System . Collections . Generic ;
6
7
using Unity . Profiling ;
7
8
using UnityEngine ;
8
9
9
- namespace Microsoft . MixedReality . Toolkit . Input
10
+ namespace Microsoft . MixedReality . Toolkit . Utilities
10
11
{
11
12
/// <summary>
12
13
/// Provides some predefined parameters for eye gaze smoothing and saccade detection.
13
14
/// </summary>
14
- public abstract class BaseEyeGazeDataProvider : BaseInputDeviceManager , IMixedRealityEyeGazeDataProvider , IMixedRealityEyeSaccadeProvider
15
+ public class EyeGazeSmoother : IMixedRealityEyeSaccadeProvider
15
16
{
16
- /// <summary>
17
- /// Constructor.
18
- /// </summary>
19
- /// <param name="inputSystem">The <see cref="Microsoft.MixedReality.Toolkit.Input.IMixedRealityInputSystem"/> instance that receives data from this provider.</param>
20
- /// <param name="name">Friendly name of the service.</param>
21
- /// <param name="priority">Service priority. Used to determine order of instantiation.</param>
22
- /// <param name="profile">The service's configuration profile.</param>
23
- public BaseEyeGazeDataProvider (
24
- IMixedRealityInputSystem inputSystem ,
25
- string name ,
26
- uint priority ,
27
- BaseMixedRealityProfile profile ) : base ( inputSystem , name , priority , profile ) { }
28
-
29
- /// <inheritdoc />
30
- public bool SmoothEyeTracking { get ; set ; } = false ;
31
-
32
- /// <inheritdoc />
33
- public IMixedRealityEyeSaccadeProvider SaccadeProvider => this ;
34
-
35
17
/// <inheritdoc />
36
18
public event Action OnSaccade ;
37
19
@@ -50,56 +32,21 @@ public BaseEyeGazeDataProvider(
50
32
private Ray saccade_initialGazePoint ;
51
33
private readonly List < Ray > saccade_newGazeCluster = new List < Ray > ( ) ;
52
34
53
- /// <inheritdoc />
54
- public override void Initialize ( )
55
- {
56
- #if UNITY_EDITOR && UNITY_WSA && UNITY_2019_3_OR_NEWER
57
- Utilities . Editor . UWPCapabilityUtility . RequireCapability (
58
- UnityEditor . PlayerSettings . WSACapability . GazeInput ,
59
- GetType ( ) ) ;
60
- #endif // UNITY_EDITOR && UNITY_WSA && UNITY_2019_3_OR_NEWER
61
-
62
- if ( Application . isPlaying )
63
- {
64
- ReadProfile ( ) ;
65
- }
66
-
67
- base . Initialize ( ) ;
68
- }
69
-
70
- private void ReadProfile ( )
71
- {
72
- if ( ConfigurationProfile == null )
73
- {
74
- Debug . LogError ( $ "{ GetType ( ) } requires a configuration profile to run properly.") ;
75
- return ;
76
- }
77
-
78
- MixedRealityEyeTrackingProfile profile = ConfigurationProfile as MixedRealityEyeTrackingProfile ;
79
- if ( profile == null )
80
- {
81
- Debug . LogError ( $ "{ GetType ( ) } 's configuration profile must be a MixedRealityEyeTrackingProfile.") ;
82
- return ;
83
- }
84
-
85
- SmoothEyeTracking = profile . SmoothEyeTracking ;
86
- }
87
-
88
- private static readonly ProfilerMarker SmoothGazePerfMarker = new ProfilerMarker ( "[MRTK] BaseEyeGazeDataProvider.SmoothGaze" ) ;
35
+ private static readonly ProfilerMarker SmoothGazePerfMarker = new ProfilerMarker ( "[MRTK] EyeGazeSmoother.SmoothGaze" ) ;
89
36
90
37
/// <summary>
91
38
/// Smooths eye gaze by detecting saccades and tracking gaze clusters.
92
39
/// </summary>
93
40
/// <param name="newGaze">The ray to smooth.</param>
94
41
/// <returns>The smoothed ray.</returns>
95
- protected Ray SmoothGaze ( Ray ? newGaze )
42
+ public Ray SmoothGaze ( Ray newGaze )
96
43
{
97
44
using ( SmoothGazePerfMarker . Auto ( ) )
98
45
{
99
46
if ( ! oldGaze . HasValue )
100
47
{
101
48
oldGaze = newGaze ;
102
- return newGaze . Value ;
49
+ return newGaze ;
103
50
}
104
51
105
52
Ray smoothedGaze = new Ray ( ) ;
@@ -109,12 +56,12 @@ protected Ray SmoothGaze(Ray? newGaze)
109
56
// apart, we check for clusters of gaze points instead.
110
57
// 1. If the user's gaze points are far enough apart, this may be a saccade, but also could be an outlier.
111
58
// So, let's mark it as a potential saccade.
112
- if ( IsSaccading ( oldGaze . Value , newGaze . Value ) && confidenceOfSaccade == 0 )
59
+ if ( IsSaccading ( oldGaze . Value , newGaze ) && confidenceOfSaccade == 0 )
113
60
{
114
61
confidenceOfSaccade ++ ;
115
62
saccade_initialGazePoint = oldGaze . Value ;
116
63
saccade_newGazeCluster . Clear ( ) ;
117
- saccade_newGazeCluster . Add ( newGaze . Value ) ;
64
+ saccade_newGazeCluster . Add ( newGaze ) ;
118
65
}
119
66
// 2. If we have a potential saccade marked, let's check if the new points are within the proximity of
120
67
// the initial saccade point.
@@ -127,19 +74,19 @@ protected Ray SmoothGaze(Ray? newGaze)
127
74
// amount of time resulting in a cluster of gaze points.
128
75
for ( int i = 0 ; i < saccade_newGazeCluster . Count ; i ++ )
129
76
{
130
- if ( IsSaccading ( saccade_newGazeCluster [ i ] , newGaze . Value ) )
77
+ if ( IsSaccading ( saccade_newGazeCluster [ i ] , newGaze ) )
131
78
{
132
79
confidenceOfSaccade = 0 ;
133
80
}
134
81
135
82
// Meanwhile we want to make sure that we are still looking sufficiently far away from our
136
83
// original gaze point before saccading.
137
- if ( ! IsSaccading ( saccade_initialGazePoint , newGaze . Value ) )
84
+ if ( ! IsSaccading ( saccade_initialGazePoint , newGaze ) )
138
85
{
139
86
confidenceOfSaccade = 0 ;
140
87
}
141
88
}
142
- saccade_newGazeCluster . Add ( newGaze . Value ) ;
89
+ saccade_newGazeCluster . Add ( newGaze ) ;
143
90
}
144
91
else if ( confidenceOfSaccade == confidenceOfSaccadeThreshold )
145
92
{
@@ -149,22 +96,22 @@ protected Ray SmoothGaze(Ray? newGaze)
149
96
// Saccade-dependent local smoothing
150
97
if ( isSaccading )
151
98
{
152
- smoothedGaze . direction = newGaze . Value . direction ;
153
- smoothedGaze . origin = newGaze . Value . origin ;
99
+ smoothedGaze . direction = newGaze . direction ;
100
+ smoothedGaze . origin = newGaze . origin ;
154
101
confidenceOfSaccade = 0 ;
155
102
}
156
103
else
157
104
{
158
- smoothedGaze . direction = oldGaze . Value . direction * smoothFactorNormalized + newGaze . Value . direction * ( 1 - smoothFactorNormalized ) ;
159
- smoothedGaze . origin = oldGaze . Value . origin * smoothFactorNormalized + newGaze . Value . origin * ( 1 - smoothFactorNormalized ) ;
105
+ smoothedGaze . direction = oldGaze . Value . direction * smoothFactorNormalized + newGaze . direction * ( 1 - smoothFactorNormalized ) ;
106
+ smoothedGaze . origin = oldGaze . Value . origin * smoothFactorNormalized + newGaze . origin * ( 1 - smoothFactorNormalized ) ;
160
107
}
161
108
162
109
oldGaze = smoothedGaze ;
163
110
return smoothedGaze ;
164
111
}
165
112
}
166
113
167
- private static readonly ProfilerMarker IsSaccadingPerfMarker = new ProfilerMarker ( "[MRTK] BaseEyeGazeDataProvider .IsSaccading" ) ;
114
+ private static readonly ProfilerMarker IsSaccadingPerfMarker = new ProfilerMarker ( "[MRTK] EyeGazeSmoother .IsSaccading" ) ;
168
115
169
116
private bool IsSaccading ( Ray rayOld , Ray rayNew )
170
117
{
0 commit comments