Tilt Five™ Unity API  1.3.0
 
Loading...
Searching...
No Matches
TiltFiveManager.cs
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-2022 Tilt Five, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16using System;
17using System.Collections;
18using UnityEngine;
19
20#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
21using UnityEngine.InputSystem;
22#endif
23
24using TiltFive;
26
27namespace TiltFive
28{
29
33 [DisallowMultipleComponent]
34#if !UNITY_2019_1_OR_NEWER || !INPUTSYSTEM_AVAILABLE
35 // Workaround to enable inputs to be collected before other scripts execute their Update() functions.
36 // This is unnecessary if we're using the Input System's OnBeforeUpdate() to collect fresh inputs.
37 [DefaultExecutionOrder(-500)]
38#else
39 // If the Input System's OnBeforeUpdate is available, set TiltFiveManager's execution order to be very late.
40 // This is desirable in two similar scenarios:
41 // - Our Update() executes last, providing the freshest pose data possible to any scripts using LateUpdate().
42 // - Our LateUpdate() executes last, providing the freshest pose data possible before we render to the glasses.
43 [DefaultExecutionOrder(500)]
44#endif
45 public class TiltFiveManager : TiltFive.SingletonComponent<TiltFiveManager>, ISceneInfo
46 {
51
56
61
62 // TODO: Make {left,right}WandSettings into the members actually holding the data. These are
63 // kept for prefab compatibility reasons, but will eventually switch. Please start using
64 // the new names from your own code.
65 [Obsolete("primaryWandSettings is deprecated, please update to use left/right based on user preference instead.")]
67 [Obsolete("secondaryWandSettings is deprecated, please update to use left/right based on user preference instead.")]
69
74 #pragma warning disable 618 // this is for compatibility; disable obsolete warning
76 set => secondaryWandSettings = value;
77 #pragma warning restore 618
78 }
79
84 #pragma warning disable 618 // this is for compatibility; disable obsolete warning
86 set => primaryWandSettings = value;
87 #pragma warning restore 618
88 }
89
94
99
100#if UNITY_EDITOR
104 public EditorSettings editorSettings = new EditorSettings();
105
106#endif
107
108 private bool needsDriverUpdateNotifiedOnce = false;
109 private bool needsDriverUpdateErroredOnce = false;
110
111 [SerializeField]
113
117 protected override void Awake()
118 {
119 base.Awake();
120
121 // Apply log settings
122 Log.LogLevel = logSettings.level;
123 Log.TAG = logSettings.TAG;
124
126 {
127 Log.Warn("Failed to send application info to the T5 Control Panel.");
128 enabled = false;
129 }
130
132
133 spectatorSettings.spectatorCamera = glassesSettings.cameraTemplate;
134 spectatorSettings.glassesMirrorMode = glassesSettings.glassesMirrorMode;
135 spectatorSettings.spectatedPlayer = playerSettings.PlayerIndex;
136 }
137
138#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
142 private void OnBeforeUpdate()
143 {
144#if UNITY_EDITOR
145 if (UnityEditor.EditorApplication.isPaused)
146 {
147 return;
148 }
149#endif
150 if (Player.scanningForPlayers)
151 {
152 return;
153 }
155 Player.ScanForNewPlayers();
156 Wand.GetLatestInputs(); // Should only be executed once per frame
157
158 // OnBeforeUpdate can get called multiple times per frame. Unity seems to not properly utilize the camera positions for rendering
159 // if they are updated after Late Update and before render, causing a disparity between render pose and camera position leading to
160 // shaky displays in the headset. To avoid this, we prevent updating the camera positions during the BeforeRender Input State.
161 if (UnityEngine.InputSystem.LowLevel.InputState.currentUpdateType != UnityEngine.InputSystem.LowLevel.InputUpdateType.BeforeRender)
162 {
163 Update();
164 }
165 }
166#endif
167
171 void Update()
172 {
173#if !UNITY_2019_1_OR_NEWER || !INPUTSYSTEM_AVAILABLE
175 Player.ScanForNewPlayers();
176 Wand.GetLatestInputs(); // Should only be executed once per frame
177#endif
180
181 var spectatedPlayer = spectatorSettings.spectatedPlayer;
182 if (Glasses.TryGetPreviewPose(spectatedPlayer, out var spectatedPlayerPose))
183 {
184 spectatorSettings.spectatorCamera?.transform.SetPositionAndRotation(
185 spectatedPlayerPose.position,
186 spectatedPlayerPose.rotation);
187 }
188 }
189
190
195 {
196 // Trackables should be updated just before rendering occurs,
197 // after all Update() calls are completed.
198 // This allows any Game Board movements to be finished before we base the
199 // Glasses/Wand poses off of its pose, preventing perceived jittering.
201 }
202
206 private void GetLatestPoseData()
207 {
211 }
212
224 public bool NeedsDriverUpdate()
225 {
227 {
228 try
229 {
231 bool needsUpdate = compatibility == ServiceCompatibility.Incompatible;
232
233 if (needsUpdate)
234 {
236 {
237 Log.Warn("Incompatible Tilt Five service. Please update driver package.");
239 }
240 }
241 else
242 {
243 // Not incompatible. Reset the incompatibility warning.
245 }
246 return needsUpdate;
247 }
248 catch (System.DllNotFoundException e)
249 {
250 Log.Info(
251 "Could not connect to Tilt Five plugin for compatibility check: {0}",
252 e.Message);
254 }
255 catch (System.Exception e)
256 {
257 Log.Error(e.Message);
259 }
260 }
261
262 // Failed to communicate with Tilt Five plugin at some point, so don't know whether
263 // an update is needed or not. Just say no.
264 return false;
265 }
266
270 private void OnEnable()
271 {
272 try
273 {
275 }
276 catch (System.DllNotFoundException e)
277 {
278 Log.Info(
279 "Could not connect to Tilt Five plugin for setting max glasses: {0}",
280 e.Message);
281 }
282 catch (System.Exception e)
283 {
284 Log.Error(e.Message);
285 }
286
289
290#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
291 InputSystem.onBeforeUpdate += OnBeforeUpdate;
292#endif
293 }
294
295 private void OnDisable()
296 {
297#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
298 InputSystem.onBeforeUpdate -= OnBeforeUpdate;
299#endif
300 Player.OnDisable();
301 }
302
303 private void OnDestroy()
304 {
305 Player.OnDisable();
306 }
307
308 private void OnApplicationQuit()
309 {
310 OnDisable();
311 }
312
313 // There's a longstanding bug where UnityPluginUnload isn't called.
314 // - https://forum.unity.com/threads/unitypluginunload-never-called.414066/
315 // - https://gamedev.stackexchange.com/questions/200118/unity-native-plugin-unitypluginload-is-called-but-unitypluginunload-is-not
316 // - https://issuetracker.unity3d.com/issues/unitypluginunload-is-never-called-in-a-standalone-build
317 // Work around this by invoking it via Application.quitting.
318 private static void Quit()
319 {
320 try
321 {
323 }
324 catch (System.DllNotFoundException)
325 {
326 // Nothing to report on quit if the plugin isn't present
327 }
328 catch (System.Exception e)
329 {
330 Log.Error(e.Message);
331 }
332 }
333
334 [RuntimeInitializeOnLoadMethod]
335 private static void RunOnStart()
336 {
337 Application.quitting += Quit;
338 }
339
341 {
342 // Warn developers if they've left the glassesSettings camera template field empty, since it's still required for the original TiltFiveManager
344 {
345 Log.Warn("No camera template detected in TiltFiveManager's glassesSettings. A camera template is required.");
346 }
347
348 // We don't expose any global settings like SpectatorSettings in TiltFiveManager's custom inspector,
349 // though they're still accessible from scripts.
350 // Just synchronize spectatorSettings from TiltFiveManager's glassesSettings as needed.
351 spectatorSettings.spectatorCamera = glassesSettings.cameraTemplate;
352 spectatorSettings.glassesMirrorMode = glassesSettings.glassesMirrorMode;
353
354 // Make sure that the spectated player isn't set to a player index higher than what TiltFiveManager supports
355 var highestSupportedPlayer = (PlayerIndex)GetSupportedPlayerCount();
356 if (spectatorSettings.spectatedPlayer > highestSupportedPlayer)
357 {
358 Log.Warn($"Invalid spectatorSettings.spectatedPlayer [{spectatorSettings.spectatedPlayer}]. TiltFiveManager only supports one player.");
359 spectatorSettings.spectatedPlayer = highestSupportedPlayer;
360 }
361 }
362
364 {
365 /* In an initial implementation of TiltFiveManager's internal PlayerSettings object, we initialized
366 * a new PlayerSettings in Awake() and set its internal settings objects to TiltFiveManager's internal settings objects.
367 *
368 * However, this introduced a bug. The settings values in TiltFiveManager's custom inspector couldn't be
369 * modified when the editor was in play mode, which would be a fairly significant quality of life issue for developers.
370 *
371 * I'm a bit fuzzy on the underlying mechanism, but the issue seemed to be that in the TiltFiveManager's
372 * custom inspector code, the SerializedProperty API (for GlassesSettings, WandSettings, ScaleSettings, etc)
373 * couldn't apply edits to the underlying settings objects if they were owned/shared by multiple parent classes
374 * (e.g. the same GlassesSettings can't be owned by both a TiltFiveManager and a PlayerSettings without
375 * breaking SerializedProperty's ability to modify the GlassesSettings).
376 *
377 * So the fix was to stop sharing.
378 * Instead of building a PlayerSettings internally on Awake() that uses TiltFiveManager's existing settings objects,
379 * we build one that has its own unique internal settings objects, and any time an edit gets made,
380 * OnValidate() does a shallow copy to those objects using RefreshPlayerSettings(). */
381
382 if(playerSettings == null)
383 {
384 return;
385 }
386 playerSettings.PlayerIndex = PlayerIndex.One;
387
388 if (glassesSettings != null)
389 {
390 playerSettings.glassesSettings = glassesSettings.Copy();
391 }
392 if (rightWandSettings != null)
393 {
394 playerSettings.rightWandSettings = rightWandSettings.Copy();
395 }
396 if (leftWandSettings != null)
397 {
398 playerSettings.leftWandSettings = leftWandSettings.Copy();
399 }
400 if (gameBoardSettings != null)
401 {
402 playerSettings.gameboardSettings = gameBoardSettings.Copy();
403 }
404 if (scaleSettings != null)
405 {
406 playerSettings.scaleSettings = scaleSettings.Copy();
407 }
408 }
409
410#if UNITY_EDITOR
411
415 void OnValidate()
416 {
417 Log.LogLevel = logSettings.level;
418 Log.TAG = logSettings.TAG;
419
420 if (scaleSettings != null)
421 {
422 scaleSettings.contentScaleRatio = Mathf.Clamp(scaleSettings.contentScaleRatio, ScaleSettings.MIN_CONTENT_SCALE_RATIO, float.MaxValue);
423 }
424
425 if (leftWandSettings != null)
426 {
427 leftWandSettings.controllerIndex = ControllerIndex.Left;
428 }
429 if (rightWandSettings != null)
430 {
431 rightWandSettings.controllerIndex = ControllerIndex.Right;
432 }
433
434 if (playerSettings != null)
435 {
437 }
438
439 if (spectatorSettings != null)
440 {
442 }
443 }
444
448 void OnDrawGizmos()
449 {
450 if (enabled && gameBoardSettings.currentGameBoard != null)
451 {
453 }
454 }
455
456#endif
457
458 #region ISceneInfo Implementation
459
460 public float GetScaleToUWRLD_UGBD()
461 {
463 }
464
465 public Pose GetGameboardPose()
466 {
467 return new Pose(gameBoardSettings.gameBoardCenter, Quaternion.Euler(gameBoardSettings.gameBoardRotation));
468 }
469
470 public Camera GetEyeCamera()
471 {
472 return Glasses.GetLeftEye(PlayerIndex.One);
473 }
474
476 {
477 return 1; // TODO: Change this if we decide to include spectators with TiltFiveManager
478 }
479
480 public bool IsActiveAndEnabled()
481 {
482 return isActiveAndEnabled;
483 }
484
485 #endregion ISceneInfo Implementation
486 }
487
488}
static bool SetApplicationInfo()
Definition: Display.cs:144
Vector3 gameBoardRotation
The game board rotation or focal rotational offset.
Vector3 gameBoardCenter
The game board position or focal position offset.
GameBoard currentGameBoard
The game board is the window into the game world, as well as the origin about which the glasses/wand ...
float gameBoardScale
The game board's scale multiplies the perceived size of objects in the scene.
The Glasses API and runtime.
Definition: Glasses.cs:35
static Camera GetLeftEye(PlayerIndex playerIndex)
Definition: Glasses.cs:305
static bool TryGetPreviewPose(PlayerIndex playerIndex, out Pose pose)
Attempts to get the position and orientation of the specified player's glasses, smoothed for on-scree...
Definition: Glasses.cs:285
static void Reset(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings=null, PlayerIndex playerIndex=PlayerIndex.None)
Reset this T:TiltFive.Glasses.
Definition: Glasses.cs:149
static void Update(GlassesSettings glassesSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
Updates this T:TiltFive.Glasses.
Definition: Glasses.cs:201
GlassesSettings encapsulates all configuration data used by the Glasses' tracking runtime to compute ...
Camera cameraTemplate
The camera used as a template for creating the eye cameras at runtime.
GlassesMirrorMode glassesMirrorMode
The Logger.
Definition: Log.cs:42
static void Warn(string m, params object[] list)
WARN logging function call.
Definition: Log.cs:166
static void Info(string m, params object[] list)
INFO logging function call.
Definition: Log.cs:140
static void Error(string m, params object[] list)
ERROR logging function call.
Definition: Log.cs:127
static void UnloadWorkaround()
static ServiceCompatibility GetServiceCompatibility()
static void SetMaxDesiredGlasses(byte maxCount)
Provides access to player settings and functionality.
Definition: Player.cs:16
ScaleSettings contains the scale data used to translate between Unity units and the user's physical s...
const float MIN_CONTENT_SCALE_RATIO
float contentScaleRatio
The scaling ratio relates physical distances to world-space units.
float GetScaleToUWRLD_UGBD(float gameboardScale)
PlayerIndex spectatedPlayer
The player that will have their perspective mirrored on screen.
Camera spectatorCamera
The camera used for rendering the onscreen preview.
The Tilt Five manager.
LogSettings logSettings
The log settings.
SpectatorSettings spectatorSettings
The spectator camera's runtime configuration data.
GameBoardSettings gameBoardSettings
The game board runtime configuration data.
void OnEnable()
Called when the GameObject is enabled.
override void Awake()
Awake this instance.
WandSettings rightWandSettings
The wand runtime configuration data for the right hand wand.
void Update()
Update this instance.
PlayerSettings playerSettings
WandSettings secondaryWandSettings
void LateUpdate()
Update this instance after all components have finished executing their Update() functions.
void GetLatestPoseData()
Obtains the latest pose for all trackable objects.
ScaleSettings scaleSettings
The scale conversion runtime configuration data.
bool NeedsDriverUpdate()
Check if a driver update is needed.
GlassesSettings glassesSettings
The glasses runtime configuration data.
WandSettings leftWandSettings
The wand runtime configuration data for the left hand wand.
WandSettings primaryWandSettings
The Wand API and runtime.
Definition: Wand.cs:56
static void Update(WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings, PlayerIndex playerIndex=PlayerIndex.One)
Definition: Wand.cs:152
Wand Settings encapsulates all configuration data used by the Wand's tracking runtime to compute the ...
Definition: Wand.cs:38
Definition: Log.cs:21
ServiceCompatibility
Whether the running service is compatible.
ControllerIndex
Since wands are all physically identical (they have no "handedness"), it doesn't make sense to addres...
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)