forked from microsoft/MixedRealityToolkit-Unity
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStabilizationPlaneModifier.cs
More file actions
283 lines (246 loc) · 10.3 KB
/
StabilizationPlaneModifier.cs
File metadata and controls
283 lines (246 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using HoloToolkit.Unity.InputModule;
using UnityEngine;
#if UNITY_WSA
#if UNITY_2017_2_OR_NEWER
using UnityEngine.XR.WSA;
#else
using UnityEngine.VR.WSA;
#endif
#endif
namespace HoloToolkit.Unity
{
/// <summary>
/// StabilizationPlaneModifier handles the setting of the stabilization plane in several ways.
/// </summary>
public class StabilizationPlaneModifier : Singleton<StabilizationPlaneModifier>
{
[Tooltip("Checking enables SetFocusPointForFrame to set the stabilization plane.")]
public bool SetStabilizationPlane = true;
[Tooltip("When lerping, use unscaled time. This is useful for games that have a pause mechanism or otherwise adjust the game timescale.")]
public bool UseUnscaledTime = true;
[Tooltip("Lerp speed when moving focus point closer.")]
public float LerpStabilizationPlanePowerCloser = 4.0f;
[Tooltip("Lerp speed when moving focus point farther away.")]
public float LerpStabilizationPlanePowerFarther = 7.0f;
[SerializeField, Tooltip("Used to temporarily override the location of the stabilization plane.")]
private Transform targetOverride;
public Transform TargetOverride
{
get
{
return targetOverride;
}
set
{
if (targetOverride != value)
{
targetOverride = value;
if (targetOverride)
{
targetOverridePreviousPosition = targetOverride.position;
}
}
}
}
[SerializeField, Tooltip("Keeps track of position-based velocity for the target object.")]
private bool trackVelocity;
public bool TrackVelocity
{
get
{
return trackVelocity;
}
set
{
trackVelocity = value;
if (TargetOverride)
{
targetOverridePreviousPosition = TargetOverride.position;
}
}
}
[Tooltip("Use the GazeManager class to set the plane to the gazed upon hologram. If disabled, the plane will always be at a constant distance.")]
public bool UseGazeManager = true;
[Tooltip("Default distance to set plane if plane is gaze-locked or if no object is hit.")]
public float DefaultPlaneDistance = 2.0f;
[Tooltip("Visualize the plane at runtime.")]
public bool DrawGizmos;
/// <summary>
/// Position of the plane in world space.
/// </summary>
private Vector3 planePosition;
/// <summary>
/// Current distance of the plane from the user's head. Only used when not using the target override
/// or the GazeManager to set the plane's position.
/// </summary>
private float currentPlaneDistance = 4.0f;
/// <summary>
/// Tracks the previous position of the target override object. Used if velocity is being tracked.
/// </summary>
private Vector3 targetOverridePreviousPosition;
/// <summary>
/// Updates the focus point for every frame after all objects have finished moving.
/// </summary>
private void LateUpdate()
{
if (SetStabilizationPlane)
{
float deltaTime = UseUnscaledTime
? Time.unscaledDeltaTime
: Time.deltaTime;
if (TargetOverride != null)
{
ConfigureTransformOverridePlane(deltaTime);
}
else if (UseGazeManager)
{
ConfigureGazeManagerPlane(deltaTime);
}
else
{
ConfigureFixedDistancePlane(deltaTime);
}
}
}
/// <summary>
/// Called by Unity when this script is loaded or a value is changed in the inspector.
/// Only called in editor, ensures that the property values always match the corresponding member variables.
/// </summary>
private void OnValidate()
{
TrackVelocity = trackVelocity;
TargetOverride = targetOverride;
}
/// <summary>
/// Gets the origin of the gaze for purposes of placing the stabilization plane
/// </summary>
private Vector3 GazeOrigin
{
get
{
if (GazeManager.IsInitialized)
{
return GazeManager.Instance.GazeOrigin;
}
return CameraCache.Main.transform.position;
}
}
/// <summary>
/// Gets the direction of the gaze for purposes of placing the stabilization plane
/// </summary>
private Vector3 GazeNormal
{
get
{
if (GazeManager.IsInitialized)
{
return GazeManager.Instance.GazeNormal;
}
return CameraCache.Main.transform.forward;
}
}
/// <summary>
/// Gets the position hit on the object the user is gazing at, if gaze tracking is supported.
/// </summary>
/// <param name="hitPosition">The position at which gaze ray intersects with an object.</param>
/// <returns>True if gaze is supported and an object was hit by gaze, otherwise false.</returns>
private bool TryGetGazeHitPosition(out Vector3 hitPosition)
{
if (GazeManager.IsInitialized)
{
hitPosition = GazeManager.Instance.HitPosition;
return true;
}
hitPosition = Vector3.zero;
return false;
}
/// <summary>
/// Configures the stabilization plane to update its position based on an object in the scene.
/// </summary>
private void ConfigureTransformOverridePlane(float deltaTime)
{
planePosition = TargetOverride.position;
Vector3 velocity = Vector3.zero;
if (TrackVelocity)
{
velocity = UpdateVelocity(deltaTime);
}
#if UNITY_WSA
// Place the plane at the desired depth in front of the user and billboard it to the gaze origin.
HolographicSettings.SetFocusPointForFrame(planePosition, -GazeNormal, velocity);
#endif
}
/// <summary>
/// Configures the stabilization plane to update its position based on what your gaze intersects in the scene.
/// </summary>
private void ConfigureGazeManagerPlane(float deltaTime)
{
Vector3 gazeOrigin = GazeOrigin;
Vector3 gazeDirection = GazeNormal;
// Calculate the delta between gaze origin's position and current hit position. If no object is hit, use default distance.
float focusPointDistance;
Vector3 gazeHitPosition;
if (TryGetGazeHitPosition(out gazeHitPosition))
{
focusPointDistance = (gazeOrigin - gazeHitPosition).magnitude;
}
else
{
focusPointDistance = DefaultPlaneDistance;
}
float lerpPower = focusPointDistance > currentPlaneDistance ? LerpStabilizationPlanePowerFarther
: LerpStabilizationPlanePowerCloser;
// Smoothly move the focus point from previous hit position to new position.
currentPlaneDistance = Mathf.Lerp(currentPlaneDistance, focusPointDistance, lerpPower * deltaTime);
planePosition = gazeOrigin + (gazeDirection * currentPlaneDistance);
#if UNITY_WSA
HolographicSettings.SetFocusPointForFrame(planePosition, -gazeDirection, Vector3.zero);
#endif
}
/// <summary>
/// Configures the stabilization plane to update based on a fixed distance away from you.
/// </summary>
private void ConfigureFixedDistancePlane(float deltaTime)
{
Vector3 gazeOrigin = GazeOrigin;
Vector3 gazeNormal = GazeNormal;
float lerpPower = DefaultPlaneDistance > currentPlaneDistance ? LerpStabilizationPlanePowerFarther
: LerpStabilizationPlanePowerCloser;
// Smoothly move the focus point from previous hit position to new position.
currentPlaneDistance = Mathf.Lerp(currentPlaneDistance, DefaultPlaneDistance, lerpPower * deltaTime);
planePosition = gazeOrigin + (gazeNormal * currentPlaneDistance);
#if UNITY_WSA
HolographicSettings.SetFocusPointForFrame(planePosition, -gazeNormal, Vector3.zero);
#endif
}
/// <summary>
/// Tracks the velocity of the target object to be used as a hint for the plane stabilization.
/// </summary>
private Vector3 UpdateVelocity(float deltaTime)
{
// Roughly calculate the velocity based on previous position, current position, and frame time.
Vector3 velocity = (TargetOverride.position - targetOverridePreviousPosition) / deltaTime;
targetOverridePreviousPosition = TargetOverride.position;
return velocity;
}
/// <summary>
/// When in editor, draws a magenta quad that visually represents the stabilization plane.
/// </summary>
private void OnDrawGizmos()
{
if (Application.isPlaying && DrawGizmos)
{
Vector3 focalPlaneNormal = -GazeNormal;
Vector3 planeUp = Vector3.Cross(Vector3.Cross(focalPlaneNormal, Vector3.up), focalPlaneNormal);
Gizmos.matrix = Matrix4x4.TRS(planePosition, Quaternion.LookRotation(focalPlaneNormal, planeUp), new Vector3(4.0f, 3.0f, 0.01f));
Color gizmoColor = Color.magenta;
gizmoColor.a = 0.5f;
Gizmos.color = gizmoColor;
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
Gizmos.DrawCube(Vector3.zero, Vector3.one);
}
}
}
}