SteamVR.cs 31 KB

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