34 public sealed class Glasses : Singleton<Glasses>
36 #region Private Fields
41 private Dictionary<GlassesHandle, GlassesCore> glassesCores =
new Dictionary<GlassesHandle, GlassesCore>();
43 private HashSet<GlassesHandle> incomingHandles =
new HashSet<GlassesHandle>();
44 private HashSet<GlassesHandle> lostHandles =
new HashSet<GlassesHandle>();
49 private GlassesHandle? defaultGlassesHandle;
66 #region Public Classes
68 public class DisplayInfo
70 public DisplayInfo(Vector2Int framebufferDimensions)
72 this.framebufferDimensions = framebufferDimensions;
80 public int height => framebufferDimensions.y;
89 public readonly RenderTextureFormat nativeTextureFormat = RenderTextureFormat.ARGB32;
92 private readonly Vector2Int framebufferDimensions =
new Vector2Int(1216, 768);
105 [Obsolete(
"Glasses.updated is deprecated. Please use Glasses.IsTracked() instead.",
true)]
112 [Obsolete(
"Glasses.configured is deprecated. Please use Player.IsConnected() instead.",
true)]
113 public static bool configured => GetPlayerOneGlassesCore()?.configured ??
false;
118 [Obsolete(
"Glasses.position is deprecated. Please use Glasses.TryGetPose() and Pose.position instead.",
true)]
119 public static Vector3
position => GetPlayerOneGlassesCore()?.Pose_UnityWorldSpace.position ?? Vector3.zero;
124 [Obsolete(
"Glasses.rotation is deprecated. Please use Glasses.TryGetPose() and Pose.rotation instead.",
true)]
125 public static Quaternion
rotation => GetPlayerOneGlassesCore()?.Pose_UnityWorldSpace.rotation ?? Quaternion.identity;
130 [Obsolete(
"Glasses.forward is deprecated. Please use Glasses.TryGetPose() and Pose.forward instead.",
true)]
131 public static Vector3
forward => GetPlayerOneGlassesCore()?.Pose_UnityWorldSpace.forward ?? Vector3.forward;
136 [Obsolete(
"Glasses.right is deprecated. Please use Glasses.TryGetPose() and Pose.right instead.",
true)]
137 public static Vector3
right => GetPlayerOneGlassesCore()?.Pose_UnityWorldSpace.right ?? Vector3.right;
142 [Obsolete(
"Glasses.up is deprecated. Please use Glasses.TryGetPose() and Pose.up instead.",
true)]
143 public static Vector3
up => GetPlayerOneGlassesCore()?.Pose_UnityWorldSpace.up ?? Vector3.up;
149 [Obsolete(
"Glasses.leftEyePosition is deprecated. Please use Glasses.GetLeftEye() and Transform.position",
true)]
150 public static Vector3
leftEyePosition => GetPlayerOneGlassesCore()?.eyePositions[AREyes.EYE_LEFT] ?? Vector3.zero;
155 [Obsolete(
"Glasses.rightEyePosition is deprecated. Please use Glasses.GetRightEye() and Transform.position",
true)]
156 public static Vector3
rightEyePosition => GetPlayerOneGlassesCore()?.eyePositions[AREyes.EYE_RIGHT] ?? Vector3.zero;
161 [Obsolete(
"Glasses.glassesAvailable is deprecated. Please use Player.IsConnected() instead.",
true)]
164 #endregion Public Fields
167 #region Public Functions
176 return Player.TryGetGlassesHandle(playerIndex, out var glassesHandle)
180#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
190 public static bool TryGetGlassesDevice(
PlayerIndex playerIndex, out GlassesDevice glassesDevice)
192 if(!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
194 glassesDevice =
null;
198 return TryGetGlassesDevice(glassesHandle, out glassesDevice);
212 if (!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
231 if(!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
240#if TILT_FIVE_ENABLE_PROJECTOR_EXTRINSICS_ADJUSTMENTS
241 public static bool TrySetProjectorExtrinsicsAdjustment(
PlayerIndex playerIndex,
float[] args)
243 if (!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
247 return TrySetProjectorExtrinsicsAdjustment(glassesHandle, args);
250 public static bool SetSingleEyeMode(
PlayerIndex playerIndex, AREyes eye)
252 if (!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
256 return SetSingleEyeMode(glassesHandle, eye);
268 if(
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle) && Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
270 pose = glassesCore.Pose_UnityWorldSpace;
286 if (
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle) && Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
288 pose = glassesCore.previewCore.Pose_UnityWorldSpace;
307 if(!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
321 if (!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
335 if (!
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
342 #region Deprecated Public Functions
350 [Obsolete(
"Glasses.headPoseUpdated is deprecated. Please use Glasses.IsTracked() instead",
true)]
353 if (playerIndex ==
PlayerIndex.None || !
Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
358 return Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore)
359 && glassesCore.IsTracked;
367 [Obsolete(
"Converted to be an internal function.",
true)]
370 Reset(playerIndex, glassesSettings, spectatorSettings);
382 [Obsolete(
"Converted to be an internal function.",
true)]
385 return Validate(playerIndex, glassesSettings, spectatorSettings);
392 [Obsolete(
"Converted to be an internal function.",
true)]
395 UpdateAllGlassesCores(glassesSettings, scaleSettings, gameBoardSettings);
403 [Obsolete(
"Deprecated in favor of Player.IsConnected().",
true)]
406 return Player.TryGetGlassesHandle(playerIndex, out var glassesHandle)
410 [Obsolete(
"Converted to be an internal function.",
true)]
411 public static void ScanForGlasses() { Scan(); }
413 #endregion Deprecated Public Functions
416 #endregion Public Functions
419 #region Internal Functions
421 internal static void Scan()
424 UInt64[] glassesHandles =
new UInt64[
GlassesSettings.MAX_SUPPORTED_GLASSES_COUNT];
425 Debug.Assert(glassesHandles.Length <= Byte.MaxValue);
426 byte glassesCount = (byte)glassesHandles.Length;
431 var refreshResult =
NativePlugin.RefreshGlassesAvailable();
432 result =
NativePlugin.GetGlassesHandles(ref glassesCount, glassesHandles);
434 catch (System.Exception e)
436 Log.Error($
"Error getting glasses handles: {e.Message}");
440 var glassesCores = Instance.glassesCores;
441 var incomingHandles = Instance.incomingHandles;
442 var lostHandles = Instance.lostHandles;
444 incomingHandles.Clear();
448 if (result != NativePlugin.T5_RESULT_SUCCESS)
450 foreach (var keyValuePair
in glassesCores)
452 var lostHandle = keyValuePair.Key;
453 var glassesCore = keyValuePair.Value;
455 glassesCore.Dispose();
456 lostHandles.Add(lostHandle);
458 glassesCores.Clear();
463 for (
int i = 0; i < glassesCount; i++)
465 incomingHandles.Add(glassesHandles[i]);
469 if (!glassesCores.ContainsKey(glassesHandles[i]) && !Player.AllSupportedPlayersConnected())
471#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
472 glassesCores[glassesHandles[i]] =
new GlassesDeviceCore(glassesHandles[i]);
474 glassesCores[glassesHandles[i]] =
new GlassesCore(glassesHandles[i]);
480 foreach (var currentHandle
in glassesCores.Keys)
482 if (!incomingHandles.Contains(currentHandle))
484 lostHandles.Add(currentHandle);
487 foreach (var lostHandle
in lostHandles)
489 glassesCores[lostHandle].Dispose();
490 glassesCores.Remove(lostHandle);
495 if (!Instance.defaultGlassesHandle.HasValue && result == 0 && glassesCount > 0)
497 Instance.defaultGlassesHandle = glassesHandles[0];
501 if (Instance.defaultGlassesHandle.HasValue && !glassesCores.ContainsKey(Instance.defaultGlassesHandle.Value))
503 Instance.defaultGlassesHandle =
null;
507 internal static void Reset(
PlayerIndex playerIndex, GlassesSettings glassesSettings, SpectatorSettings spectatorSettings =
null)
509 if (spectatorSettings ==
null && !TryGetSpectatorSettings(out spectatorSettings))
511 Log.Error(
"Glasses.Reset() could not find any spectator settings.");
518 foreach (var glassesCore
in Instance.glassesCores.Values)
520 glassesCore.Reset(glassesSettings, spectatorSettings);
525 if (Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
527 Reset(glassesSettings, spectatorSettings, glassesHandle);
531 internal static void Reset(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings, GlassesHandle glassesHandle)
533 if (Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore) && spectatorSettings !=
null)
535 glassesCore.Reset(glassesSettings, spectatorSettings);
539 internal static bool Validate(
PlayerIndex playerIndex, GlassesSettings glassesSettings, SpectatorSettings spectatorSettings =
null)
541 if (!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
546 if (spectatorSettings ==
null && !TryGetSpectatorSettings(out spectatorSettings))
551 return Validate(glassesSettings, spectatorSettings, glassesHandle);
554 internal static bool Validate(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings, GlassesHandle glassesHandle)
556 return Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore)
557 && glassesCore.Validate(glassesSettings, spectatorSettings);
560 internal static void UpdateAllGlassesCores(GlassesSettings glassesSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
562 if (!TryGetSpectatorSettings(out var spectatorSettings))
568 foreach (var glassesCore
in Instance.glassesCores.Values)
570 glassesCore.Update(glassesSettings, scaleSettings, gameBoardSettings, spectatorSettings);
574 internal static void Update(GlassesHandle glassesHandle, GlassesSettings glassesSettings, ScaleSettings scaleSettings,
575 GameBoardSettings gameBoardSettings, SpectatorSettings spectatorSettings)
577 if (Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
579 glassesCore.Update(glassesSettings, scaleSettings, gameBoardSettings, spectatorSettings);
583 internal static bool IsTracked(GlassesHandle glassesHandle)
585 return Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore)
586 && glassesCore.IsTracked;
589 internal static bool IsConnected(GlassesHandle glassesHandle)
591 return Instance.glassesCores.ContainsKey(glassesHandle);
594#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
595 internal static bool TryGetGlassesDevice(GlassesHandle glassesHandle, out GlassesDevice glassesDevice)
597 if(!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore)
598 || !(glassesCore is GlassesDeviceCore glassesDeviceCore))
600 glassesDevice =
null;
604 glassesDevice = glassesDeviceCore.glassesDevice;
611 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
617 displayInfo = glassesCore.displayInfo;
621 internal static bool TryGetFriendlyName(GlassesHandle glassesHandle, out
string friendlyName)
623 if(!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
629 return glassesCore.TryGetFriendlyName(out friendlyName);
632#if TILT_FIVE_ENABLE_PROJECTOR_EXTRINSICS_ADJUSTMENTS
633 internal static bool TrySetProjectorExtrinsicsAdjustment(GlassesHandle glassesHandle,
float[] args)
635 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
639 return glassesCore.TrySetProjectorExtrinsicsAdjustment(args);
642 internal static bool SetSingleEyeMode(GlassesHandle glassesHandle, AREyes eye)
644 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
648 return glassesCore.SetSingleEyeMode(eye);
658 internal static GlassesHandle? GetDefaultGlassesHandle()
660 var defaultGlassesHandle = Instance.defaultGlassesHandle;
661 return defaultGlassesHandle.HasValue && Instance.glassesCores.ContainsKey(defaultGlassesHandle.Value)
662 ? defaultGlassesHandle
666 internal static void SetDefaultGlassesHandle(GlassesHandle glassesHandle)
668 Instance.defaultGlassesHandle = glassesHandle;
671 internal static GlassesHandle[] GetAllConnectedGlassesHandles()
673 var keys = Instance.glassesCores.Keys;
674 GlassesHandle[] glassesHandles =
new GlassesHandle[keys.Count];
675 keys.CopyTo(glassesHandles, 0);
676 return glassesHandles;
679 internal static void OnDisable()
681 foreach (var glassesCore
in Instance.glassesCores.Values)
683 glassesCore.Dispose();
685 Instance.glassesCores.Clear();
688 #endregion Internal Functions
691 #region Private Functions
693 private static GameObject
GetPoseRoot(GlassesHandle glassesHandle)
695 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
699 return glassesCore.headPose.gameObject;
702 private static Camera
GetLeftEye(GlassesHandle glassesHandle)
704 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
708 return glassesCore.leftEye;
711 private static Camera
GetRightEye(GlassesHandle glassesHandle)
713 if (!Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
718 return glassesCore.rightEye;
721 private static GlassesCore GetPlayerOneGlassesCore()
723 if(Player.TryGetGlassesHandle(
PlayerIndex.One, out var glassesHandle)
724 && Instance.glassesCores.TryGetValue(glassesHandle, out var glassesCore))
731 private static bool TryGetSpectatorSettings(out SpectatorSettings spectatorSettings)
733 if (TiltFiveSingletonHelper.TryGetISceneInfo(out var sceneInfo))
735 if (sceneInfo is TiltFiveManager2 tiltFiveManager2)
737 spectatorSettings = tiltFiveManager2.spectatorSettings;
741 if (sceneInfo is TiltFiveManager tiltFiveManager)
743 spectatorSettings = tiltFiveManager.spectatorSettings;
748 spectatorSettings =
null;
755 #region Private Classes
757 private class BaseGlassesCore : TrackableCore<GlassesSettings, T5_GlassesPose>, IDisposable
759 public GlassesHandle glassesHandle;
761 public GameObject headPoseRoot;
762 public Transform headPose => headPoseRoot.transform;
764 private T5_GlassesPoseUsage glassesPoseUsage;
766 private DisplayInfo _displayInfo;
768 public DisplayInfo displayInfo => _displayInfo;
777 private readonly Vector3 DEFAULT_GLASSES_POSITION_GAME_BOARD_SPACE =
new Vector3(0f, 0.5f, -0.5f);
786 private readonly Quaternion DEFAULT_GLASSES_ROTATION_GAME_BOARD_SPACE = Quaternion.Euler(
new Vector3(-45f, 0f, 0f));
788 public BaseGlassesCore(
789 GlassesHandle glassesHandle,
790 T5_GlassesPoseUsage glassesPoseUsage,
793 this.glassesHandle = glassesHandle;
794 this.glassesPoseUsage = glassesPoseUsage;
795 headPoseRoot =
new GameObject(name);
797 var displayDimensions =
new Vector2Int();
798 if (!Display.GetDisplayDimensions(
this.glassesHandle, ref displayDimensions))
800 Log.Warn(
"Could not retrieve display settings from the plugin; display dimensions may be incorrect.");
804 _displayInfo =
new DisplayInfo(displayDimensions);
808 public virtual void Dispose()
810 GameObject.Destroy(headPoseRoot);
819 protected override void Update(
820 GlassesSettings glassesSettings,
821 ScaleSettings scaleSettings,
822 GameBoardSettings gameBoardSettings)
825 base.Update(glassesSettings, scaleSettings, gameBoardSettings);
828 protected override void SetDefaultPoseGameboardSpace(GlassesSettings settings)
830 pose_USTAGE =
new Pose(
831 DEFAULT_GLASSES_POSITION_GAME_BOARD_SPACE,
832 DEFAULT_GLASSES_ROTATION_GAME_BOARD_SPACE);
835 protected override void SetPoseUnityWorldSpace(
836 ScaleSettings scaleSettings,
837 GameBoardSettings gameBoardSettings)
839 pose_UWRLD = GameboardToWorldSpace(pose_USTAGE, scaleSettings, gameBoardSettings);
842 protected override bool TryCheckConnected(out
bool connected)
848 protected override bool TryGetStateFromPlugin(out T5_GlassesPose glassesPose, out
bool poseIsValid)
850 T5_GlassesPose glassesPoseResult =
new T5_GlassesPose { };
852 int result = NativePlugin.T5_RESULT_UNKNOWN_ERROR;
855 result = NativePlugin.GetGlassesPose(
857 ref glassesPoseResult,
860 catch (System.Exception e)
862 Log.Error(e.Message);
865 poseIsValid = result == NativePlugin.T5_RESULT_SUCCESS && glassesPoseResult.GameboardType !=
GameboardType.GameboardType_None;
866 glassesPose = glassesPoseResult;
867 return result == NativePlugin.T5_RESULT_SUCCESS;
870 protected override void SetPoseGameboardSpace(
871 in T5_GlassesPose glassesPose,
872 GlassesSettings glassesSettings,
873 ScaleSettings scaleSettings,
874 GameBoardSettings gameboardSettings)
876 pose_USTAGE = GetPoseGameboardSpace(glassesPose);
879 protected override void SetInvalidPoseGameboardSpace(
880 in T5_GlassesPose glassesPose,
881 GlassesSettings settings,
882 ScaleSettings scaleSettings,
883 GameBoardSettings gameboardSettings)
885 var newPose_GameboardSpace = GetPoseGameboardSpace(glassesPose);
887 if (!isTracked && settings.RejectUntrackedPositionData)
889 switch (settings.FailureMode)
891 case TrackableSettings.TrackingFailureMode.FreezePosition:
892 pose_USTAGE =
new Pose(pose_USTAGE.position, newPose_GameboardSpace.rotation);
895 case TrackableSettings.TrackingFailureMode.FreezePositionAndRotation:
898 case TrackableSettings.TrackingFailureMode.SnapToDefault:
900 if (settings.usePreviewPose)
902 pose_USTAGE =
new Pose(WorldToGameboardSpace(settings.previewPose.position, scaleSettings, gameboardSettings),
903 WorldToGameboardSpace(settings.previewPose.rotation, gameboardSettings));
912 pose_USTAGE = newPose_GameboardSpace;
916 protected override void SetDrivenObjectTransform(
917 GlassesSettings settings,
918 ScaleSettings scaleSettings,
919 GameBoardSettings gameBoardSettings)
921 if (!isTracked && settings.RejectUntrackedPositionData)
923 switch (settings.FailureMode)
925 case TrackableSettings.TrackingFailureMode.FreezePosition:
926 headPose.SetPositionAndRotation(headPose.position, pose_UWRLD.rotation);
929 case TrackableSettings.TrackingFailureMode.FreezePositionAndRotation:
932 case TrackableSettings.TrackingFailureMode.SnapToDefault:
934 if (settings.usePreviewPose)
936 headPose.SetPositionAndRotation(
937 settings.previewPose.position,
938 settings.previewPose.rotation);
947 headPose.SetPositionAndRotation(pose_UWRLD.position, pose_UWRLD.rotation);
951 private Pose GetPoseGameboardSpace(T5_GlassesPose glassesPose)
967 Quaternion rotToDC_STAGE = Quaternion.AngleAxis((-Mathf.PI / 2f) * Mathf.Rad2Deg, Vector3.right);
969 Quaternion rotToSTAGE_DC = Quaternion.Inverse(rotToDC_STAGE);
971 Quaternion rotToGLS_STAGE = glassesPose.RotationToGLS_STAGE;
973 Quaternion rotToGLS_DC = rotToGLS_STAGE * rotToSTAGE_DC;
975 Quaternion rotToUSTAGE_UGLS =
new Quaternion(rotToGLS_DC.x, rotToGLS_DC.y, -rotToGLS_DC.z, rotToGLS_DC.w);
978 Vector3 posOfUGLS_USTAGE = ConvertPosSTAGEToUSTAGE(glassesPose.PosOfGLS_STAGE);
980 return new Pose(posOfUGLS_USTAGE, rotToUSTAGE_UGLS);
991 private class GlassesPreviewCore : BaseGlassesCore
993 public GlassesPreviewCore(GlassesHandle glassesHandle) :
994 base(glassesHandle, T5_GlassesPoseUsage.SpectatorPresentation, $
"Glasses {glassesHandle} preview")
1003 public new void Update(
1004 GlassesSettings glassesSettings,
1005 ScaleSettings scaleSettings,
1006 GameBoardSettings gameBoardSettings)
1009 base.Update(glassesSettings, scaleSettings, gameBoardSettings);
1012 protected override void SetDrivenObjectTransform(GlassesSettings settings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
1014 base.SetDrivenObjectTransform(settings, scaleSettings, gameBoardSettings);
1022 private class GlassesCore : BaseGlassesCore
1025 public GameObject baseObject;
1026 public string friendlyName;
1031 public bool configured =
false;
1033 public Dictionary<AREyes, Vector3> eyePositions =
new Dictionary<AREyes, Vector3>()
1035 { AREyes.EYE_LEFT,
new Vector3() },
1036 { AREyes.EYE_RIGHT,
new Vector3() }
1039 public Dictionary<AREyes, Quaternion> eyeRotations =
new Dictionary<AREyes, Quaternion>()
1041 { AREyes.EYE_LEFT,
new Quaternion() },
1042 { AREyes.EYE_RIGHT,
new Quaternion() }
1045 public GlassesPreviewCore previewCore;
1047 public GlassesCore(GlassesHandle glassesHandle) :
1048 base(glassesHandle, T5_GlassesPoseUsage.GlassesPresentation, $
"Glasses {glassesHandle}")
1050 if(!Player.TryGetPlayerIndex(glassesHandle, out playerIndex))
1052 Player.TryAddPlayer(glassesHandle, out playerIndex);
1054 previewCore =
new GlassesPreviewCore(glassesHandle);
1055 CameraImage.Initialize(glassesHandle);
1057 Log.Info($
"Glasses {glassesHandle} connected.");
1060 public override void Dispose()
1062 GameObject.Destroy(splitStereoCamera);
1063 GameObject.Destroy(baseObject);
1064 CameraImage.RemoveCore(glassesHandle);
1065 previewCore.Dispose();
1069 Log.Info($
"Glasses {glassesHandle} (\"{friendlyName}\") disconnected");
1075 private SplitStereoCamera splitStereoCamera =
null;
1077 internal Camera leftEye => splitStereoCamera?.leftEyeCamera;
1078 internal Camera rightEye => splitStereoCamera?.rightEyeCamera;
1085 public virtual void Reset(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings)
1087 base.Reset(glassesSettings);
1093 Log.Error($
"Required Camera assignment missing from { spectatorSettings.GetType() }. Check Spectator settings in Tilt Five Manager");
1098 if (glassesSettings.tiltFiveXR)
1102 if (
null == splitStereoCamera)
1105 GameObject spectatorCameraObject = spectatorSettings.
spectatorCamera.gameObject;
1108 splitStereoCamera = spectatorCameraObject.AddComponent<SplitStereoCamera>();
1109 if (
null == headPoseRoot)
1112 headPoseRoot =
new GameObject($
"Glasses {glassesHandle}");
1113 previewCore =
new GlassesPreviewCore(glassesHandle);
1117#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
1118 if(glassesSettings.
objectTemplate.TryGetComponent<PlayerInput>(out var playerInput))
1120 Log.Warn(
"Attaching a PlayerInput component to the Object Template is not recommended," +
1121 " as the Object Template does not persist across scene loads." +
1122 "Consider using the Input Template instead.");
1125 baseObject = GameObject.Instantiate(glassesSettings.
objectTemplate, headPoseRoot.transform);
1126 baseObject.name = $
"{baseObject.transform.parent.name} - Prefab {playerIndex}";
1128 splitStereoCamera.Initialize(headPoseRoot, glassesSettings, spectatorSettings, displayInfo);
1134 TryGetFriendlyName(out friendlyName);
1145 public bool Validate(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings)
1149 valid &= splitStereoCamera !=
null
1150 && glassesSettings.cameraTemplate == splitStereoCamera.cameraTemplate
1151 && spectatorSettings == splitStereoCamera.spectatorSettings;
1156 public bool TryGetFriendlyName(out
string friendlyName)
1158 T5_StringUTF8 friendlyNameResult =
"";
1159 int result = NativePlugin.T5_RESULT_UNKNOWN_ERROR;
1163 result = NativePlugin.GetGlassesFriendlyName(glassesHandle, ref friendlyNameResult);
1165 catch (System.Exception e)
1167 Log.Error($
"Error getting friendly name: {e.Message}");
1171 friendlyName = (result == NativePlugin.T5_RESULT_SUCCESS)
1172 ? friendlyNameResult
1178 friendlyNameResult.Dispose();
1181 return result == NativePlugin.T5_RESULT_SUCCESS;
1184#if TILT_FIVE_ENABLE_PROJECTOR_EXTRINSICS_ADJUSTMENTS
1185 public bool TrySetProjectorExtrinsicsAdjustment(
float[] args)
1191 result = NativePlugin.SetProjectorExtrinsicsAdjustment(glassesHandle, args);
1193 catch (System.Exception e)
1195 Log.Error($
"Error setting projector extrinsics adjustment: ${e.Message}");
1197 return result == NativePlugin.T5_RESULT_SUCCESS;
1200 public bool SetSingleEyeMode(AREyes eye)
1202 Camera leftEyeCamera = splitStereoCamera.leftEyeCamera;
1203 Camera rightEyeCamera = splitStereoCamera.rightEyeCamera;
1204 if (leftEyeCamera ==
null || rightEyeCamera ==
null)
1206 Log.Error(
"Eye camera null during call to SetSingleEyeMode()");
1212 case AREyes.EYE_LEFT:
1215 leftEyeCamera.enabled =
true;
1216 rightEyeCamera.enabled =
false;
1218 RenderTexture rt = RenderTexture.active;
1219 RenderTexture.active = rightEyeCamera.targetTexture;
1220 GL.Viewport(rightEyeCamera.pixelRect);
1221 GL.Clear(
true,
true, Color.clear);
1222 RenderTexture.active = rt;
1225 case AREyes.EYE_RIGHT:
1228 leftEyeCamera.enabled =
false;
1229 rightEyeCamera.enabled =
true;
1231 RenderTexture rt = RenderTexture.active;
1232 RenderTexture.active = leftEyeCamera.targetTexture;
1233 GL.Viewport(leftEyeCamera.pixelRect);
1234 GL.Clear(
true,
true, Color.clear);
1235 RenderTexture.active = rt;
1238 case AREyes.EYE_MAX:
1239 leftEyeCamera.enabled =
true;
1240 rightEyeCamera.enabled =
true;
1251 public void Update(GlassesSettings glassesSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings, SpectatorSettings spectatorSettings)
1253 if (
null == glassesSettings)
1255 Log.Error(
"GlassesSettings configuration required for Glasses tracking Update.");
1259 if (
null == splitStereoCamera)
1261 Log.Error($
"Stereo camera(s) missing from Glasses {glassesHandle} - aborting Update.");
1265 if (glassesSettings.
cameraTemplate != splitStereoCamera.cameraTemplate)
1267 Log.Warn(
"Found mismatched template Cameras in GlassesCore Update - should call Reset.");
1271 if (spectatorSettings != splitStereoCamera.spectatorSettings)
1273 Log.Warn(
"Found mismatched spectator settings in GlassesCore Update - should call Reset.");
1278 base.Update(glassesSettings, scaleSettings, gameBoardSettings);
1279 previewCore.Update(glassesSettings, scaleSettings, gameBoardSettings);
1282 splitStereoCamera.glassesHandle = glassesHandle;
1283 splitStereoCamera.enabled = isConnected;
1286 splitStereoCamera.glassesSettings = glassesSettings;
1287 splitStereoCamera.spectatorSettings = spectatorSettings;
1290 splitStereoCamera.UseSpectatorCamera = Player.IsConnected(spectatorSettings.
spectatedPlayer)
1291 && Player.TryGetGlassesHandle(spectatorSettings.
spectatedPlayer, out var spectatorGlassesHandle)
1292 && spectatorGlassesHandle == glassesHandle;
1295 float scaleToUWRLD_USTAGE = scaleSettings.GetScaleToWorldSpaceFromGameboardSpace(gameBoardSettings.
gameBoardScale);
1296 float scaleToUSTAGE_UWRLD = 1.0f / scaleToUWRLD_USTAGE;
1312 float ipd_USTAGE = GlassesSettings.DEFAULT_IPD_STAGE;
1313 if(!Display.GetGlassesIPD(glassesHandle, ref ipd_USTAGE) && isConnected)
1315 Log.Error(
"Failed to obtain Glasses IPD");
1317 float ipd_UWRLD = scaleToUWRLD_USTAGE * ipd_USTAGE;
1318 Vector3 eyeOffset = (headPose.right.normalized * (ipd_UWRLD * 0.5f));
1321 eyePositions[AREyes.EYE_LEFT] = headPose.position - eyeOffset;
1322 eyeRotations[AREyes.EYE_LEFT] = headPose.rotation;
1325 eyePositions[AREyes.EYE_RIGHT] = headPose.position + eyeOffset;
1326 eyeRotations[AREyes.EYE_RIGHT] = headPose.rotation;
1328 Camera leftEyeCamera = splitStereoCamera.leftEyeCamera;
1329 if (
null != leftEyeCamera)
1331 GameObject leftEye = leftEyeCamera.gameObject;
1332 leftEye.transform.position = eyePositions[AREyes.EYE_LEFT];
1333 leftEye.transform.rotation = eyeRotations[AREyes.EYE_LEFT];
1336 leftEyeCamera.nearClipPlane = glassesSettings.nearClipPlane / scaleToUSTAGE_UWRLD;
1337 leftEyeCamera.farClipPlane = glassesSettings.farClipPlane / scaleToUSTAGE_UWRLD;
1338 leftEyeCamera.fieldOfView = glassesSettings.fieldOfView;
1339 leftEyeCamera.cullingMask = glassesSettings.
cullingMask;
1342 Camera rightEyeCamera = splitStereoCamera.rightEyeCamera;
1343 if (
null != rightEyeCamera)
1345 GameObject rightEye = rightEyeCamera.gameObject;
1346 rightEye.transform.position = eyePositions[AREyes.EYE_RIGHT];
1347 rightEye.transform.rotation = eyeRotations[AREyes.EYE_RIGHT];
1350 rightEyeCamera.nearClipPlane = glassesSettings.nearClipPlane / scaleToUSTAGE_UWRLD;
1351 rightEyeCamera.farClipPlane = glassesSettings.farClipPlane / scaleToUSTAGE_UWRLD;
1352 rightEyeCamera.fieldOfView = glassesSettings.fieldOfView;
1353 rightEyeCamera.cullingMask = glassesSettings.
cullingMask;
1357 if (!TryGetFriendlyName(out glassesSettings.friendlyName))
1359 glassesSettings.friendlyName = GlassesSettings.DEFAULT_FRIENDLY_NAME;
1363 protected override void SetDrivenObjectTransform(GlassesSettings settings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
1365 base.SetDrivenObjectTransform(settings, scaleSettings, gameBoardSettings);
1369#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
1370 private class GlassesDeviceCore : GlassesCore, IDisposable
1372 internal GlassesDevice glassesDevice;
1373 internal GameObject playerTemplateObject;
1375 private enum TrackingState :
int
1382 public GlassesDeviceCore(GlassesHandle glassesHandle) : base(glassesHandle)
1384 Input.AddGlassesDevice(playerIndex);
1385 glassesDevice = Input.GetGlassesDevice(playerIndex);
1387 if(glassesDevice !=
null && glassesDevice.added)
1389 InputSystem.EnableDevice(glassesDevice);
1391 if(TiltFiveManager2.IsInstantiated)
1393 TiltFiveManager2.Instance.RefreshInputDevicePairings();
1397 public override void Dispose()
1401 if(glassesDevice !=
null && glassesDevice.added)
1403 if (glassesDevice.LeftWand !=
null)
1407 if (glassesDevice.RightWand !=
null)
1411 InputSystem.DisableDevice(glassesDevice);
1412 Input.RemoveGlassesDevice(playerIndex);
1414 GameObject.Destroy(playerTemplateObject);
1417 public override void Reset(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings)
1419 base.Reset(glassesSettings, spectatorSettings);
1421 if(glassesSettings.playerTemplate)
1423 playerTemplateObject = GameObject.Instantiate(glassesSettings.playerTemplate);
1424 if(TiltFiveManager2.IsInstantiated)
1426 TiltFiveManager2.Instance.RefreshInputDevicePairings();
1431 protected override void SetDrivenObjectTransform(GlassesSettings settings, ScaleSettings scaleSettings, GameBoardSettings gameboardSettings)
1433 base.SetDrivenObjectTransform(settings, scaleSettings, gameboardSettings);
1435 if(glassesDevice ==
null || !glassesDevice.added)
1441 QueueDeltaStateEvent(glassesDevice.devicePosition, pose_UWRLD.position);
1442 QueueDeltaStateEvent(glassesDevice.centerEyePosition, pose_UWRLD.position);
1443 QueueDeltaStateEvent(glassesDevice.leftEyePosition, eyePositions[AREyes.EYE_LEFT]);
1444 QueueDeltaStateEvent(glassesDevice.rightEyePosition, eyePositions[AREyes.EYE_RIGHT]);
1447 QueueDeltaStateEvent(glassesDevice.deviceRotation, pose_UWRLD.rotation);
1448 QueueDeltaStateEvent(glassesDevice.centerEyeRotation, pose_UWRLD.rotation);
1449 QueueDeltaStateEvent(glassesDevice.leftEyeRotation, pose_UWRLD.rotation);
1450 QueueDeltaStateEvent(glassesDevice.rightEyeRotation, pose_UWRLD.rotation);
1453 QueueDeltaStateEvent(glassesDevice.RawPosition, pose_USTAGE.position);
1454 QueueDeltaStateEvent(glassesDevice.RawLeftEyePosition, WorldToGameboardSpace(eyePositions[AREyes.EYE_LEFT], scaleSettings, gameboardSettings));
1455 QueueDeltaStateEvent(glassesDevice.RawRightEyePosition, WorldToGameboardSpace(eyePositions[AREyes.EYE_RIGHT], scaleSettings, gameboardSettings));
1458 QueueDeltaStateEvent(glassesDevice.RawRotation, pose_USTAGE.rotation);
1459 QueueDeltaStateEvent(glassesDevice.leftEyeRotation, pose_USTAGE.rotation);
1460 QueueDeltaStateEvent(glassesDevice.rightEyeRotation, pose_USTAGE.rotation);
1462 InputSystem.QueueDeltaStateEvent(glassesDevice.isTracked, isTracked);
1464 var trackingState = TrackingState.Tracking;
1467 trackingState = settings.FailureMode == TrackableSettings.TrackingFailureMode.FreezePosition
1468 ? TrackingState.Limited
1469 : TrackingState.None;
1472 InputSystem.QueueDeltaStateEvent(glassesDevice.trackingState, (
int)trackingState);
1475 private static void QueueDeltaStateEvent(Vector3Control vector3Control, Vector3 delta)
1477 InputSystem.QueueDeltaStateEvent(vector3Control.x, delta.x);
1478 InputSystem.QueueDeltaStateEvent(vector3Control.y, delta.y);
1479 InputSystem.QueueDeltaStateEvent(vector3Control.z, delta.z);
1484 private static void QueueDeltaStateEvent(QuaternionControl quaternionControl, Quaternion delta)
1486 InputSystem.QueueDeltaStateEvent(quaternionControl.w, delta.w);
1487 InputSystem.QueueDeltaStateEvent(quaternionControl.x, delta.x);
1488 InputSystem.QueueDeltaStateEvent(quaternionControl.y, delta.y);
1489 InputSystem.QueueDeltaStateEvent(quaternionControl.z, delta.z);
1494 #endregion Private Classes