SteamVR.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Access to SteamVR system (hmd) and compositor (distort) interfaces.
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using Valve.VR;
  8. using System.IO;
  9. using System.Linq;
  10. #if UNITY_2017_2_OR_NEWER
  11. using UnityEngine.XR;
  12. #else
  13. using XRSettings = UnityEngine.VR.VRSettings;
  14. using XRDevice = UnityEngine.VR.VRDevice;
  15. #endif
  16. namespace Valve.VR
  17. {
  18. public class SteamVR : System.IDisposable
  19. {
  20. // Use this to check if SteamVR is currently active without attempting
  21. // to activate it in the process.
  22. public static bool active { get { return _instance != null; } }
  23. // Set this to false to keep from auto-initializing when calling SteamVR.instance.
  24. private static bool _enabled = true;
  25. public static bool enabled
  26. {
  27. get
  28. {
  29. if (!XRSettings.enabled)
  30. enabled = false;
  31. return _enabled;
  32. }
  33. set
  34. {
  35. _enabled = value;
  36. if (_enabled)
  37. {
  38. Initialize();
  39. }
  40. else
  41. {
  42. SafeDispose();
  43. }
  44. }
  45. }
  46. private static SteamVR _instance;
  47. public static SteamVR instance
  48. {
  49. get
  50. {
  51. #if UNITY_EDITOR
  52. if (!Application.isPlaying)
  53. return null;
  54. #endif
  55. if (!enabled)
  56. return null;
  57. if (_instance == null)
  58. {
  59. _instance = CreateInstance();
  60. // If init failed, then auto-disable so scripts don't continue trying to re-initialize things.
  61. if (_instance == null)
  62. _enabled = false;
  63. }
  64. return _instance;
  65. }
  66. }
  67. public enum InitializedStates
  68. {
  69. None,
  70. Initializing,
  71. InitializeSuccess,
  72. InitializeFailure,
  73. }
  74. public static InitializedStates initializedState = InitializedStates.None;
  75. public static void Initialize(bool forceUnityVRMode = false)
  76. {
  77. if (forceUnityVRMode)
  78. {
  79. SteamVR_Behaviour.instance.InitializeSteamVR(true);
  80. return;
  81. }
  82. else
  83. {
  84. if (_instance == null)
  85. {
  86. _instance = CreateInstance();
  87. if (_instance == null)
  88. _enabled = false;
  89. }
  90. }
  91. if (_enabled)
  92. SteamVR_Behaviour.Initialize(forceUnityVRMode);
  93. }
  94. public static bool usingNativeSupport
  95. {
  96. get { return XRDevice.GetNativePtr() != System.IntPtr.Zero; }
  97. }
  98. public static SteamVR_Settings settings { get; private set; }
  99. private static void ReportGeneralErrors()
  100. {
  101. string errorLog = "<b>[SteamVR]</b> Initialization failed. ";
  102. if (XRSettings.enabled == false)
  103. errorLog += "VR may be disabled in player settings. Go to player settings in the editor and check the 'Virtual Reality Supported' checkbox'. ";
  104. if (XRSettings.supportedDevices != null && XRSettings.supportedDevices.Length > 0)
  105. {
  106. if (XRSettings.supportedDevices.Contains("OpenVR") == false)
  107. errorLog += "OpenVR is not in your list of supported virtual reality SDKs. Add it to the list in player settings. ";
  108. else if (XRSettings.supportedDevices.First().Contains("OpenVR") == false)
  109. errorLog += "OpenVR is not first in your list of supported virtual reality SDKs. <b>This is okay, but if you have an Oculus device plugged in, and Oculus above OpenVR in this list, it will try and use the Oculus SDK instead of OpenVR.</b> ";
  110. }
  111. else
  112. {
  113. errorLog += "You have no SDKs in your Player Settings list of supported virtual reality SDKs. Add OpenVR to it. ";
  114. }
  115. errorLog += "To force OpenVR initialization call SteamVR.Initialize(true). ";
  116. Debug.LogWarning(errorLog);
  117. }
  118. private static SteamVR CreateInstance()
  119. {
  120. initializedState = InitializedStates.Initializing;
  121. try
  122. {
  123. var error = EVRInitError.None;
  124. if (!SteamVR.usingNativeSupport)
  125. {
  126. ReportGeneralErrors();
  127. initializedState = InitializedStates.InitializeFailure;
  128. SteamVR_Events.Initialized.Send(false);
  129. return null;
  130. }
  131. // Verify common interfaces are valid.
  132. OpenVR.GetGenericInterface(OpenVR.IVRCompositor_Version, ref error);
  133. if (error != EVRInitError.None)
  134. {
  135. initializedState = InitializedStates.InitializeFailure;
  136. ReportError(error);
  137. ReportGeneralErrors();
  138. SteamVR_Events.Initialized.Send(false);
  139. return null;
  140. }
  141. OpenVR.GetGenericInterface(OpenVR.IVROverlay_Version, ref error);
  142. if (error != EVRInitError.None)
  143. {
  144. initializedState = InitializedStates.InitializeFailure;
  145. ReportError(error);
  146. SteamVR_Events.Initialized.Send(false);
  147. return null;
  148. }
  149. settings = SteamVR_Settings.instance;
  150. if (Application.isEditor)
  151. IdentifyEditorApplication();
  152. SteamVR_Input.IdentifyActionsFile();
  153. if (SteamVR_Settings.instance.inputUpdateMode != SteamVR_UpdateModes.Nothing || SteamVR_Settings.instance.poseUpdateMode != SteamVR_UpdateModes.Nothing)
  154. {
  155. SteamVR_Input.Initialize();
  156. #if UNITY_EDITOR
  157. if (SteamVR_Input.IsOpeningSetup())
  158. return null;
  159. #endif
  160. }
  161. }
  162. catch (System.Exception e)
  163. {
  164. Debug.LogError("<b>[SteamVR]</b> " + e);
  165. SteamVR_Events.Initialized.Send(false);
  166. return null;
  167. }
  168. _enabled = true;
  169. initializedState = InitializedStates.InitializeSuccess;
  170. SteamVR_Events.Initialized.Send(true);
  171. return new SteamVR();
  172. }
  173. static void ReportError(EVRInitError error)
  174. {
  175. switch (error)
  176. {
  177. case EVRInitError.None:
  178. break;
  179. case EVRInitError.VendorSpecific_UnableToConnectToOculusRuntime:
  180. Debug.LogWarning("<b>[SteamVR]</b> Initialization Failed! Make sure device is on, Oculus runtime is installed, and OVRService_*.exe is running.");
  181. break;
  182. case EVRInitError.Init_VRClientDLLNotFound:
  183. Debug.LogWarning("<b>[SteamVR]</b> Drivers not found! They can be installed via Steam under Library > Tools. Visit http://steampowered.com to install Steam.");
  184. break;
  185. case EVRInitError.Driver_RuntimeOutOfDate:
  186. Debug.LogWarning("<b>[SteamVR]</b> Initialization Failed! Make sure device's runtime is up to date.");
  187. break;
  188. default:
  189. Debug.LogWarning("<b>[SteamVR]</b> " + OpenVR.GetStringForHmdError(error));
  190. break;
  191. }
  192. }
  193. // native interfaces
  194. public CVRSystem hmd { get; private set; }
  195. public CVRCompositor compositor { get; private set; }
  196. public CVROverlay overlay { get; private set; }
  197. // tracking status
  198. static public bool initializing { get; private set; }
  199. static public bool calibrating { get; private set; }
  200. static public bool outOfRange { get; private set; }
  201. static public bool[] connected = new bool[OpenVR.k_unMaxTrackedDeviceCount];
  202. // render values
  203. public float sceneWidth { get; private set; }
  204. public float sceneHeight { get; private set; }
  205. public float aspect { get; private set; }
  206. public float fieldOfView { get; private set; }
  207. public Vector2 tanHalfFov { get; private set; }
  208. public VRTextureBounds_t[] textureBounds { get; private set; }
  209. public SteamVR_Utils.RigidTransform[] eyes { get; private set; }
  210. public ETextureType textureType;
  211. // hmd properties
  212. public string hmd_TrackingSystemName { get { return GetStringProperty(ETrackedDeviceProperty.Prop_TrackingSystemName_String); } }
  213. public string hmd_ModelNumber { get { return GetStringProperty(ETrackedDeviceProperty.Prop_ModelNumber_String); } }
  214. public string hmd_SerialNumber { get { return GetStringProperty(ETrackedDeviceProperty.Prop_SerialNumber_String); } }
  215. public float hmd_SecondsFromVsyncToPhotons { get { return GetFloatProperty(ETrackedDeviceProperty.Prop_SecondsFromVsyncToPhotons_Float); } }
  216. public float hmd_DisplayFrequency { get { return GetFloatProperty(ETrackedDeviceProperty.Prop_DisplayFrequency_Float); } }
  217. public string GetTrackedDeviceString(uint deviceId)
  218. {
  219. var error = ETrackedPropertyError.TrackedProp_Success;
  220. var capacity = hmd.GetStringTrackedDeviceProperty(deviceId, ETrackedDeviceProperty.Prop_AttachedDeviceId_String, null, 0, ref error);
  221. if (capacity > 1)
  222. {
  223. var result = new System.Text.StringBuilder((int)capacity);
  224. hmd.GetStringTrackedDeviceProperty(deviceId, ETrackedDeviceProperty.Prop_AttachedDeviceId_String, result, capacity, ref error);
  225. return result.ToString();
  226. }
  227. return null;
  228. }
  229. public string GetStringProperty(ETrackedDeviceProperty prop, uint deviceId = OpenVR.k_unTrackedDeviceIndex_Hmd)
  230. {
  231. var error = ETrackedPropertyError.TrackedProp_Success;
  232. var capactiy = hmd.GetStringTrackedDeviceProperty(deviceId, prop, null, 0, ref error);
  233. if (capactiy > 1)
  234. {
  235. var result = new System.Text.StringBuilder((int)capactiy);
  236. hmd.GetStringTrackedDeviceProperty(deviceId, prop, result, capactiy, ref error);
  237. return result.ToString();
  238. }
  239. return (error != ETrackedPropertyError.TrackedProp_Success) ? error.ToString() : "<unknown>";
  240. }
  241. public float GetFloatProperty(ETrackedDeviceProperty prop, uint deviceId = OpenVR.k_unTrackedDeviceIndex_Hmd)
  242. {
  243. var error = ETrackedPropertyError.TrackedProp_Success;
  244. return hmd.GetFloatTrackedDeviceProperty(deviceId, prop, ref error);
  245. }
  246. private static bool runningTemporarySession = false;
  247. public static bool InitializeTemporarySession(bool initInput = false)
  248. {
  249. if (Application.isEditor)
  250. {
  251. //bool needsInit = (!active && !usingNativeSupport && !runningTemporarySession);
  252. EVRInitError initError = EVRInitError.None;
  253. OpenVR.GetGenericInterface(OpenVR.IVRCompositor_Version, ref initError);
  254. bool needsInit = initError != EVRInitError.None;
  255. if (needsInit)
  256. {
  257. EVRInitError error = EVRInitError.None;
  258. OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
  259. if (error != EVRInitError.None)
  260. {
  261. Debug.LogError("<b>[SteamVR]</b> Error during OpenVR Init: " + error.ToString());
  262. return false;
  263. }
  264. IdentifyEditorApplication(false);
  265. SteamVR_Input.IdentifyActionsFile(false);
  266. runningTemporarySession = true;
  267. }
  268. if (initInput)
  269. {
  270. SteamVR_Input.Initialize(true);
  271. }
  272. return needsInit;
  273. }
  274. return false;
  275. }
  276. public static void ExitTemporarySession()
  277. {
  278. if (runningTemporarySession)
  279. {
  280. OpenVR.Shutdown();
  281. runningTemporarySession = false;
  282. }
  283. }
  284. #if UNITY_EDITOR
  285. public static void ShowBindingsForEditor()
  286. {
  287. bool temporarySession = InitializeTemporarySession(false);
  288. Valve.VR.EVRSettingsError bindingFlagError = Valve.VR.EVRSettingsError.None;
  289. Valve.VR.OpenVR.Settings.SetBool(Valve.VR.OpenVR.k_pch_SteamVR_Section, Valve.VR.OpenVR.k_pch_SteamVR_DebugInputBinding, true, ref bindingFlagError);
  290. if (bindingFlagError != Valve.VR.EVRSettingsError.None)
  291. Debug.LogError("<b>[SteamVR]</b> Error turning on the debug input binding flag in steamvr: " + bindingFlagError.ToString());
  292. if (Application.isPlaying == false)
  293. {
  294. IdentifyEditorApplication();
  295. SteamVR_Input.IdentifyActionsFile();
  296. }
  297. if (temporarySession)
  298. ExitTemporarySession();
  299. string bindingurl = "http://localhost:8998/dashboard/controllerbinding.html?app=" + SteamVR_Settings.instance.editorAppKey;
  300. #if UNITY_STANDALONE_WIN
  301. SteamVR_Windows_Editor_Helper.BrowserApplication browser = SteamVR_Windows_Editor_Helper.GetDefaultBrowser();
  302. if (browser == SteamVR_Windows_Editor_Helper.BrowserApplication.Unknown)
  303. {
  304. Debug.LogError("<b>[SteamVR]</b> Unfortunately we were unable to detect your default browser. You may need to manually open the controller binding UI from SteamVR if it does not open successfully. SteamVR Menu -> Devices -> Controller Input Binding. Press play in your application to get it running then select it under Current Application.");
  305. }
  306. else if (browser == SteamVR_Windows_Editor_Helper.BrowserApplication.Edge)
  307. {
  308. Debug.LogError("<b>[SteamVR]</b> Microsoft Edge sometimes has issues with opening localhost webpages. You may need to manually open the controller binding UI from SteamVR if it did not load successfully. SteamVR Menu -> Devices -> Controller Input Binding. Press play in your application to get it running then select it under Current Application.");
  309. }
  310. #endif
  311. Application.OpenURL(bindingurl); //todo: update with the actual api call
  312. }
  313. public static string GetResourcesFolderPath(bool fromAssetsDirectory = false)
  314. {
  315. SteamVR_Settings asset = ScriptableObject.CreateInstance<SteamVR_Settings>();
  316. UnityEditor.MonoScript scriptAsset = UnityEditor.MonoScript.FromScriptableObject(asset);
  317. string scriptPath = UnityEditor.AssetDatabase.GetAssetPath(scriptAsset);
  318. System.IO.FileInfo fi = new System.IO.FileInfo(scriptPath);
  319. string rootPath = fi.Directory.Parent.ToString();
  320. string resourcesPath = System.IO.Path.Combine(rootPath, "Resources");
  321. resourcesPath = resourcesPath.Replace("//", "/");
  322. resourcesPath = resourcesPath.Replace("\\\\", "\\");
  323. resourcesPath = resourcesPath.Replace("\\", "/");
  324. if (fromAssetsDirectory)
  325. {
  326. int assetsIndex = resourcesPath.IndexOf("/Assets/");
  327. resourcesPath = resourcesPath.Substring(assetsIndex + 1);
  328. }
  329. return resourcesPath;
  330. }
  331. #endif
  332. public const string defaultUnityAppKeyTemplate = "application.generated.unity.{0}.exe";
  333. public const string defaultAppKeyTemplate = "application.generated.{0}";
  334. public static string GenerateAppKey()
  335. {
  336. string productName = GenerateCleanProductName();
  337. return string.Format(defaultUnityAppKeyTemplate, productName);
  338. }
  339. public static string GenerateCleanProductName()
  340. {
  341. string productName = Application.productName;
  342. if (string.IsNullOrEmpty(productName))
  343. productName = "unnamed_product";
  344. else
  345. {
  346. productName = System.Text.RegularExpressions.Regex.Replace(Application.productName, "[^\\w\\._]", "");
  347. productName = productName.ToLower();
  348. }
  349. return productName;
  350. }
  351. private static string GetManifestFile()
  352. {
  353. string currentPath = Application.dataPath;
  354. int lastIndex = currentPath.LastIndexOf('/');
  355. currentPath = currentPath.Remove(lastIndex, currentPath.Length - lastIndex);
  356. string fullPath = Path.Combine(currentPath, "unityProject.vrmanifest");
  357. FileInfo fullManifestPath = new FileInfo(SteamVR_Settings.instance.actionsFilePath);
  358. if (File.Exists(fullPath))
  359. {
  360. string jsonText = File.ReadAllText(fullPath);
  361. SteamVR_Input_ManifestFile existingFile = Valve.Newtonsoft.Json.JsonConvert.DeserializeObject<SteamVR_Input_ManifestFile>(jsonText);
  362. if (existingFile != null && existingFile.applications != null && existingFile.applications.Count > 0 &&
  363. existingFile.applications[0].app_key != SteamVR_Settings.instance.editorAppKey)
  364. {
  365. Debug.Log("<b>[SteamVR]</b> Deleting existing VRManifest because it has a different app key.");
  366. FileInfo existingInfo = new FileInfo(fullPath);
  367. if (existingInfo.IsReadOnly)
  368. existingInfo.IsReadOnly = false;
  369. existingInfo.Delete();
  370. }
  371. if (existingFile != null && existingFile.applications != null && existingFile.applications.Count > 0 &&
  372. existingFile.applications[0].action_manifest_path != fullManifestPath.FullName)
  373. {
  374. Debug.Log("<b>[SteamVR]</b> Deleting existing VRManifest because it has a different action manifest path:" +
  375. "\nExisting:" + existingFile.applications[0].action_manifest_path +
  376. "\nNew: " + fullManifestPath.FullName);
  377. FileInfo existingInfo = new FileInfo(fullPath);
  378. if (existingInfo.IsReadOnly)
  379. existingInfo.IsReadOnly = false;
  380. existingInfo.Delete();
  381. }
  382. }
  383. if (File.Exists(fullPath) == false)
  384. {
  385. SteamVR_Input_ManifestFile manifestFile = new SteamVR_Input_ManifestFile();
  386. manifestFile.source = "Unity";
  387. SteamVR_Input_ManifestFile_Application manifestApplication = new SteamVR_Input_ManifestFile_Application();
  388. manifestApplication.app_key = SteamVR_Settings.instance.editorAppKey;
  389. manifestApplication.action_manifest_path = fullManifestPath.FullName;
  390. manifestApplication.launch_type = "url";
  391. //manifestApplication.binary_path_windows = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
  392. //manifestApplication.binary_path_linux = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
  393. //manifestApplication.binary_path_osx = SteamVR_Utils.ConvertToForwardSlashes(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
  394. manifestApplication.url = "steam://launch/";
  395. manifestApplication.strings.Add("en_us", new SteamVR_Input_ManifestFile_ApplicationString() { name = string.Format("{0} [Testing]", Application.productName) });
  396. /*
  397. var bindings = new System.Collections.Generic.List<SteamVR_Input_ManifestFile_Application_Binding>();
  398. SteamVR_Input.InitializeFile();
  399. if (SteamVR_Input.actionFile != null)
  400. {
  401. string[] bindingFiles = SteamVR_Input.actionFile.GetFilesToCopy(true);
  402. if (bindingFiles.Length == SteamVR_Input.actionFile.default_bindings.Count)
  403. {
  404. for (int bindingIndex = 0; bindingIndex < bindingFiles.Length; bindingIndex++)
  405. {
  406. SteamVR_Input_ManifestFile_Application_Binding binding = new SteamVR_Input_ManifestFile_Application_Binding();
  407. binding.binding_url = bindingFiles[bindingIndex];
  408. binding.controller_type = SteamVR_Input.actionFile.default_bindings[bindingIndex].controller_type;
  409. bindings.Add(binding);
  410. }
  411. manifestApplication.bindings = bindings;
  412. }
  413. else
  414. {
  415. Debug.LogError("<b>[SteamVR]</b> Mismatch in available binding files.");
  416. }
  417. }
  418. else
  419. {
  420. Debug.LogError("<b>[SteamVR]</b> Could not load actions file.");
  421. }
  422. */
  423. manifestFile.applications = new System.Collections.Generic.List<SteamVR_Input_ManifestFile_Application>();
  424. manifestFile.applications.Add(manifestApplication);
  425. string json = Valve.Newtonsoft.Json.JsonConvert.SerializeObject(manifestFile, Valve.Newtonsoft.Json.Formatting.Indented,
  426. new Valve.Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Valve.Newtonsoft.Json.NullValueHandling.Ignore });
  427. File.WriteAllText(fullPath, json);
  428. }
  429. return fullPath;
  430. }
  431. private static void IdentifyEditorApplication(bool showLogs = true)
  432. {
  433. //bool isInstalled = OpenVR.Applications.IsApplicationInstalled(SteamVR_Settings.instance.editorAppKey);
  434. string manifestPath = GetManifestFile();
  435. EVRApplicationError addManifestErr = OpenVR.Applications.AddApplicationManifest(manifestPath, true);
  436. if (addManifestErr != EVRApplicationError.None)
  437. Debug.LogError("<b>[SteamVR]</b> Error adding vr manifest file: " + addManifestErr.ToString());
  438. else
  439. {
  440. if (showLogs)
  441. Debug.Log("<b>[SteamVR]</b> Successfully added VR manifest to SteamVR");
  442. }
  443. int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
  444. EVRApplicationError applicationIdentifyErr = OpenVR.Applications.IdentifyApplication((uint)processId, SteamVR_Settings.instance.editorAppKey);
  445. if (applicationIdentifyErr != EVRApplicationError.None)
  446. Debug.LogError("<b>[SteamVR]</b> Error identifying application: " + applicationIdentifyErr.ToString());
  447. else
  448. {
  449. if (showLogs)
  450. Debug.Log(string.Format("<b>[SteamVR]</b> Successfully identified process as editor project to SteamVR ({0})", SteamVR_Settings.instance.editorAppKey));
  451. }
  452. }
  453. #region Event callbacks
  454. private void OnInitializing(bool initializing)
  455. {
  456. SteamVR.initializing = initializing;
  457. }
  458. private void OnCalibrating(bool calibrating)
  459. {
  460. SteamVR.calibrating = calibrating;
  461. }
  462. private void OnOutOfRange(bool outOfRange)
  463. {
  464. SteamVR.outOfRange = outOfRange;
  465. }
  466. private void OnDeviceConnected(int i, bool connected)
  467. {
  468. SteamVR.connected[i] = connected;
  469. }
  470. private void OnNewPoses(TrackedDevicePose_t[] poses)
  471. {
  472. // Update eye offsets to account for IPD changes.
  473. eyes[0] = new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Left));
  474. eyes[1] = new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Right));
  475. for (int i = 0; i < poses.Length; i++)
  476. {
  477. var connected = poses[i].bDeviceIsConnected;
  478. if (connected != SteamVR.connected[i])
  479. {
  480. SteamVR_Events.DeviceConnected.Send(i, connected);
  481. }
  482. }
  483. if (poses.Length > OpenVR.k_unTrackedDeviceIndex_Hmd)
  484. {
  485. var result = poses[OpenVR.k_unTrackedDeviceIndex_Hmd].eTrackingResult;
  486. var initializing = result == ETrackingResult.Uninitialized;
  487. if (initializing != SteamVR.initializing)
  488. {
  489. SteamVR_Events.Initializing.Send(initializing);
  490. }
  491. var calibrating =
  492. result == ETrackingResult.Calibrating_InProgress ||
  493. result == ETrackingResult.Calibrating_OutOfRange;
  494. if (calibrating != SteamVR.calibrating)
  495. {
  496. SteamVR_Events.Calibrating.Send(calibrating);
  497. }
  498. var outOfRange =
  499. result == ETrackingResult.Running_OutOfRange ||
  500. result == ETrackingResult.Calibrating_OutOfRange;
  501. if (outOfRange != SteamVR.outOfRange)
  502. {
  503. SteamVR_Events.OutOfRange.Send(outOfRange);
  504. }
  505. }
  506. }
  507. #endregion
  508. private SteamVR()
  509. {
  510. hmd = OpenVR.System;
  511. Debug.Log("<b>[SteamVR]</b> Initialized. Connected to " + hmd_TrackingSystemName + ":" + hmd_SerialNumber);
  512. compositor = OpenVR.Compositor;
  513. overlay = OpenVR.Overlay;
  514. // Setup render values
  515. uint w = 0, h = 0;
  516. hmd.GetRecommendedRenderTargetSize(ref w, ref h);
  517. sceneWidth = (float)w;
  518. sceneHeight = (float)h;
  519. float l_left = 0.0f, l_right = 0.0f, l_top = 0.0f, l_bottom = 0.0f;
  520. hmd.GetProjectionRaw(EVREye.Eye_Left, ref l_left, ref l_right, ref l_top, ref l_bottom);
  521. float r_left = 0.0f, r_right = 0.0f, r_top = 0.0f, r_bottom = 0.0f;
  522. hmd.GetProjectionRaw(EVREye.Eye_Right, ref r_left, ref r_right, ref r_top, ref r_bottom);
  523. tanHalfFov = new Vector2(
  524. Mathf.Max(-l_left, l_right, -r_left, r_right),
  525. Mathf.Max(-l_top, l_bottom, -r_top, r_bottom));
  526. textureBounds = new VRTextureBounds_t[2];
  527. textureBounds[0].uMin = 0.5f + 0.5f * l_left / tanHalfFov.x;
  528. textureBounds[0].uMax = 0.5f + 0.5f * l_right / tanHalfFov.x;
  529. textureBounds[0].vMin = 0.5f - 0.5f * l_bottom / tanHalfFov.y;
  530. textureBounds[0].vMax = 0.5f - 0.5f * l_top / tanHalfFov.y;
  531. textureBounds[1].uMin = 0.5f + 0.5f * r_left / tanHalfFov.x;
  532. textureBounds[1].uMax = 0.5f + 0.5f * r_right / tanHalfFov.x;
  533. textureBounds[1].vMin = 0.5f - 0.5f * r_bottom / tanHalfFov.y;
  534. textureBounds[1].vMax = 0.5f - 0.5f * r_top / tanHalfFov.y;
  535. // Grow the recommended size to account for the overlapping fov
  536. sceneWidth = sceneWidth / Mathf.Max(textureBounds[0].uMax - textureBounds[0].uMin, textureBounds[1].uMax - textureBounds[1].uMin);
  537. sceneHeight = sceneHeight / Mathf.Max(textureBounds[0].vMax - textureBounds[0].vMin, textureBounds[1].vMax - textureBounds[1].vMin);
  538. aspect = tanHalfFov.x / tanHalfFov.y;
  539. fieldOfView = 2.0f * Mathf.Atan(tanHalfFov.y) * Mathf.Rad2Deg;
  540. eyes = new SteamVR_Utils.RigidTransform[] {
  541. new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Left)),
  542. new SteamVR_Utils.RigidTransform(hmd.GetEyeToHeadTransform(EVREye.Eye_Right)) };
  543. switch (SystemInfo.graphicsDeviceType)
  544. {
  545. #if (UNITY_5_4)
  546. case UnityEngine.Rendering.GraphicsDeviceType.OpenGL2:
  547. #endif
  548. case UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore:
  549. case UnityEngine.Rendering.GraphicsDeviceType.OpenGLES2:
  550. case UnityEngine.Rendering.GraphicsDeviceType.OpenGLES3:
  551. textureType = ETextureType.OpenGL;
  552. break;
  553. #if !(UNITY_5_4)
  554. case UnityEngine.Rendering.GraphicsDeviceType.Vulkan:
  555. textureType = ETextureType.Vulkan;
  556. break;
  557. #endif
  558. default:
  559. textureType = ETextureType.DirectX;
  560. break;
  561. }
  562. SteamVR_Events.Initializing.Listen(OnInitializing);
  563. SteamVR_Events.Calibrating.Listen(OnCalibrating);
  564. SteamVR_Events.OutOfRange.Listen(OnOutOfRange);
  565. SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
  566. SteamVR_Events.NewPoses.Listen(OnNewPoses);
  567. }
  568. ~SteamVR()
  569. {
  570. Dispose(false);
  571. }
  572. public void Dispose()
  573. {
  574. Dispose(true);
  575. System.GC.SuppressFinalize(this);
  576. }
  577. private void Dispose(bool disposing)
  578. {
  579. SteamVR_Events.Initializing.Remove(OnInitializing);
  580. SteamVR_Events.Calibrating.Remove(OnCalibrating);
  581. SteamVR_Events.OutOfRange.Remove(OnOutOfRange);
  582. SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
  583. SteamVR_Events.NewPoses.Remove(OnNewPoses);
  584. _instance = null;
  585. }
  586. // Use this interface to avoid accidentally creating the instance in the process of attempting to dispose of it.
  587. public static void SafeDispose()
  588. {
  589. if (_instance != null)
  590. _instance.Dispose();
  591. }
  592. }
  593. }