SteamVR.cs 31 KB

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