OVRManager.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424
  1. /************************************************************************************
  2. Copyright : Copyright 2017 Oculus VR, LLC. All Rights reserved.
  3. Licensed under the Oculus VR Rift SDK License Version 3.4.1 (the "License");
  4. you may not use the Oculus VR Rift SDK except in compliance with the License,
  5. which is provided at the time of installation or download, or which
  6. otherwise accompanies this software in either electronic or hard copy form.
  7. You may obtain a copy of the License at
  8. https://developer.oculus.com/licenses/sdk-3.4.1
  9. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ************************************************************************************/
  15. #if !UNITY_5_6_OR_NEWER
  16. #error Oculus Utilities require Unity 5.6 or higher.
  17. #endif
  18. using System;
  19. using System.Collections.Generic;
  20. using UnityEngine;
  21. #if UNITY_EDITOR
  22. using UnityEditor;
  23. #endif
  24. /// <summary>
  25. /// Configuration data for Oculus virtual reality.
  26. /// </summary>
  27. public class OVRManager : MonoBehaviour
  28. {
  29. public enum TrackingOrigin
  30. {
  31. EyeLevel = OVRPlugin.TrackingOrigin.EyeLevel,
  32. FloorLevel = OVRPlugin.TrackingOrigin.FloorLevel,
  33. }
  34. public enum EyeTextureFormat
  35. {
  36. Default = OVRPlugin.EyeTextureFormat.Default,
  37. R16G16B16A16_FP = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP,
  38. R11G11B10_FP = OVRPlugin.EyeTextureFormat.R11G11B10_FP,
  39. }
  40. public enum TiledMultiResLevel
  41. {
  42. Off = OVRPlugin.TiledMultiResLevel.Off,
  43. LMSLow = OVRPlugin.TiledMultiResLevel.LMSLow,
  44. LMSMedium = OVRPlugin.TiledMultiResLevel.LMSMedium,
  45. LMSHigh = OVRPlugin.TiledMultiResLevel.LMSHigh,
  46. }
  47. /// <summary>
  48. /// Gets the singleton instance.
  49. /// </summary>
  50. public static OVRManager instance { get; private set; }
  51. /// <summary>
  52. /// Gets a reference to the active display.
  53. /// </summary>
  54. public static OVRDisplay display { get; private set; }
  55. /// <summary>
  56. /// Gets a reference to the active sensor.
  57. /// </summary>
  58. public static OVRTracker tracker { get; private set; }
  59. /// <summary>
  60. /// Gets a reference to the active boundary system.
  61. /// </summary>
  62. public static OVRBoundary boundary { get; private set; }
  63. private static OVRProfile _profile;
  64. /// <summary>
  65. /// Gets the current profile, which contains information about the user's settings and body dimensions.
  66. /// </summary>
  67. public static OVRProfile profile
  68. {
  69. get {
  70. if (_profile == null)
  71. _profile = new OVRProfile();
  72. return _profile;
  73. }
  74. }
  75. private IEnumerable<Camera> disabledCameras;
  76. float prevTimeScale;
  77. /// <summary>
  78. /// Occurs when an HMD attached.
  79. /// </summary>
  80. public static event Action HMDAcquired;
  81. /// <summary>
  82. /// Occurs when an HMD detached.
  83. /// </summary>
  84. public static event Action HMDLost;
  85. /// <summary>
  86. /// Occurs when an HMD is put on the user's head.
  87. /// </summary>
  88. public static event Action HMDMounted;
  89. /// <summary>
  90. /// Occurs when an HMD is taken off the user's head.
  91. /// </summary>
  92. public static event Action HMDUnmounted;
  93. /// <summary>
  94. /// Occurs when VR Focus is acquired.
  95. /// </summary>
  96. public static event Action VrFocusAcquired;
  97. /// <summary>
  98. /// Occurs when VR Focus is lost.
  99. /// </summary>
  100. public static event Action VrFocusLost;
  101. /// <summary>
  102. /// Occurs when Input Focus is acquired.
  103. /// </summary>
  104. public static event Action InputFocusAcquired;
  105. /// <summary>
  106. /// Occurs when Input Focus is lost.
  107. /// </summary>
  108. public static event Action InputFocusLost;
  109. /// <summary>
  110. /// Occurs when the active Audio Out device has changed and a restart is needed.
  111. /// </summary>
  112. public static event Action AudioOutChanged;
  113. /// <summary>
  114. /// Occurs when the active Audio In device has changed and a restart is needed.
  115. /// </summary>
  116. public static event Action AudioInChanged;
  117. /// <summary>
  118. /// Occurs when the sensor gained tracking.
  119. /// </summary>
  120. public static event Action TrackingAcquired;
  121. /// <summary>
  122. /// Occurs when the sensor lost tracking.
  123. /// </summary>
  124. public static event Action TrackingLost;
  125. /// <summary>
  126. /// Occurs when Health & Safety Warning is dismissed.
  127. /// </summary>
  128. //Disable the warning about it being unused. It's deprecated.
  129. #pragma warning disable 0067
  130. [Obsolete]
  131. public static event Action HSWDismissed;
  132. #pragma warning restore
  133. private static bool _isHmdPresentCached = false;
  134. private static bool _isHmdPresent = false;
  135. private static bool _wasHmdPresent = false;
  136. /// <summary>
  137. /// If true, a head-mounted display is connected and present.
  138. /// </summary>
  139. public static bool isHmdPresent
  140. {
  141. get {
  142. if (!_isHmdPresentCached)
  143. {
  144. _isHmdPresentCached = true;
  145. _isHmdPresent = OVRPlugin.hmdPresent;
  146. }
  147. return _isHmdPresent;
  148. }
  149. private set {
  150. _isHmdPresentCached = true;
  151. _isHmdPresent = value;
  152. }
  153. }
  154. /// <summary>
  155. /// Gets the audio output device identifier.
  156. /// </summary>
  157. /// <description>
  158. /// On Windows, this is a string containing the GUID of the IMMDevice for the Windows audio endpoint to use.
  159. /// </description>
  160. public static string audioOutId
  161. {
  162. get { return OVRPlugin.audioOutId; }
  163. }
  164. /// <summary>
  165. /// Gets the audio input device identifier.
  166. /// </summary>
  167. /// <description>
  168. /// On Windows, this is a string containing the GUID of the IMMDevice for the Windows audio endpoint to use.
  169. /// </description>
  170. public static string audioInId
  171. {
  172. get { return OVRPlugin.audioInId; }
  173. }
  174. private static bool _hasVrFocusCached = false;
  175. private static bool _hasVrFocus = false;
  176. private static bool _hadVrFocus = false;
  177. /// <summary>
  178. /// If true, the app has VR Focus.
  179. /// </summary>
  180. public static bool hasVrFocus
  181. {
  182. get {
  183. if (!_hasVrFocusCached)
  184. {
  185. _hasVrFocusCached = true;
  186. _hasVrFocus = OVRPlugin.hasVrFocus;
  187. }
  188. return _hasVrFocus;
  189. }
  190. private set {
  191. _hasVrFocusCached = true;
  192. _hasVrFocus = value;
  193. }
  194. }
  195. private static bool _hadInputFocus = true;
  196. /// <summary>
  197. /// If true, the app has Input Focus.
  198. /// </summary>
  199. public static bool hasInputFocus
  200. {
  201. get
  202. {
  203. return OVRPlugin.hasInputFocus;
  204. }
  205. }
  206. /// <summary>
  207. /// If true, chromatic de-aberration will be applied, improving the image at the cost of texture bandwidth.
  208. /// </summary>
  209. public bool chromatic
  210. {
  211. get {
  212. if (!isHmdPresent)
  213. return false;
  214. return OVRPlugin.chromatic;
  215. }
  216. set {
  217. if (!isHmdPresent)
  218. return;
  219. OVRPlugin.chromatic = value;
  220. }
  221. }
  222. [Header("Performance/Quality")]
  223. /// <summary>
  224. /// If true, distortion rendering work is submitted a quarter-frame early to avoid pipeline stalls and increase CPU-GPU parallelism.
  225. /// </summary>
  226. [Tooltip("If true, distortion rendering work is submitted a quarter-frame early to avoid pipeline stalls and increase CPU-GPU parallelism.")]
  227. public bool queueAhead = true;
  228. /// <summary>
  229. /// If true, Unity will use the optimal antialiasing level for quality/performance on the current hardware.
  230. /// </summary>
  231. [Tooltip("If true, Unity will use the optimal antialiasing level for quality/performance on the current hardware.")]
  232. public bool useRecommendedMSAALevel = false;
  233. /// <summary>
  234. /// If true, both eyes will see the same image, rendered from the center eye pose, saving performance.
  235. /// </summary>
  236. [SerializeField]
  237. [Tooltip("If true, both eyes will see the same image, rendered from the center eye pose, saving performance.")]
  238. private bool _monoscopic = false;
  239. public bool monoscopic
  240. {
  241. get
  242. {
  243. if (!isHmdPresent)
  244. return _monoscopic;
  245. return OVRPlugin.monoscopic;
  246. }
  247. set
  248. {
  249. if (!isHmdPresent)
  250. return;
  251. OVRPlugin.monoscopic = value;
  252. _monoscopic = value;
  253. }
  254. }
  255. /// <summary>
  256. /// If true, dynamic resolution will be enabled
  257. /// </summary>
  258. [Tooltip("If true, dynamic resolution will be enabled On PC")]
  259. public bool enableAdaptiveResolution = false;
  260. /// <summary>
  261. /// Adaptive Resolution is based on Unity engine's renderViewportScale/eyeTextureResolutionScale feature
  262. /// But renderViewportScale was broken in an array of Unity engines, this function help to filter out those broken engines
  263. /// </summary>
  264. public static bool IsAdaptiveResSupportedByEngine()
  265. {
  266. #if UNITY_2017_1_OR_NEWER
  267. return Application.unityVersion != "2017.1.0f1";
  268. #else
  269. return false;
  270. #endif
  271. }
  272. /// <summary>
  273. /// Min RenderScale the app can reach under adaptive resolution mode ( enableAdaptiveResolution = true );
  274. /// </summary>
  275. [RangeAttribute(0.5f, 2.0f)]
  276. [Tooltip("Min RenderScale the app can reach under adaptive resolution mode")]
  277. public float minRenderScale = 0.7f;
  278. /// <summary>
  279. /// Max RenderScale the app can reach under adaptive resolution mode ( enableAdaptiveResolution = true );
  280. /// </summary>
  281. [RangeAttribute(0.5f, 2.0f)]
  282. [Tooltip("Max RenderScale the app can reach under adaptive resolution mode")]
  283. public float maxRenderScale = 1.0f;
  284. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  285. /// <summary>
  286. /// If true, the MixedRealityCapture properties will be displayed
  287. /// </summary>
  288. [HideInInspector]
  289. public bool expandMixedRealityCapturePropertySheet = false;
  290. /// <summary>
  291. /// If true, Mixed Reality mode will be enabled
  292. /// </summary>
  293. [HideInInspector, Tooltip("If true, Mixed Reality mode will be enabled. It would be always set to false when the game is launching without editor")]
  294. public bool enableMixedReality = false;
  295. public enum CompositionMethod
  296. {
  297. External,
  298. Direct,
  299. Sandwich
  300. }
  301. /// <summary>
  302. /// Composition method
  303. /// </summary>
  304. [HideInInspector]
  305. public CompositionMethod compositionMethod = CompositionMethod.External;
  306. /// <summary>
  307. /// Extra hidden layers
  308. /// </summary>
  309. [HideInInspector, Tooltip("Extra hidden layers")]
  310. public LayerMask extraHiddenLayers;
  311. /// <summary>
  312. /// If true, Mixed Reality mode will use direct composition from the first web camera
  313. /// </summary>
  314. public enum CameraDevice
  315. {
  316. WebCamera0,
  317. WebCamera1,
  318. ZEDCamera
  319. }
  320. /// <summary>
  321. /// The camera device for direct composition
  322. /// </summary>
  323. [HideInInspector, Tooltip("The camera device for direct composition")]
  324. public CameraDevice capturingCameraDevice = CameraDevice.WebCamera0;
  325. /// <summary>
  326. /// Flip the camera frame horizontally
  327. /// </summary>
  328. [HideInInspector, Tooltip("Flip the camera frame horizontally")]
  329. public bool flipCameraFrameHorizontally = false;
  330. /// <summary>
  331. /// Flip the camera frame vertically
  332. /// </summary>
  333. [HideInInspector, Tooltip("Flip the camera frame vertically")]
  334. public bool flipCameraFrameVertically = false;
  335. /// <summary>
  336. /// Delay the touch controller pose by a short duration (0 to 0.5 second) to match the physical camera latency
  337. /// </summary>
  338. [HideInInspector, Tooltip("Delay the touch controller pose by a short duration (0 to 0.5 second) to match the physical camera latency")]
  339. public float handPoseStateLatency = 0.0f;
  340. /// <summary>
  341. /// Delay the foreground / background image in the sandwich composition to match the physical camera latency. The maximum duration is sandwichCompositionBufferedFrames / {Game FPS}
  342. /// </summary>
  343. [HideInInspector, Tooltip("Delay the foreground / background image in the sandwich composition to match the physical camera latency. The maximum duration is sandwichCompositionBufferedFrames / {Game FPS}")]
  344. public float sandwichCompositionRenderLatency = 0.0f;
  345. /// <summary>
  346. /// The number of frames are buffered in the SandWich composition. The more buffered frames, the more memory it would consume.
  347. /// </summary>
  348. [HideInInspector, Tooltip("The number of frames are buffered in the SandWich composition. The more buffered frames, the more memory it would consume.")]
  349. public int sandwichCompositionBufferedFrames = 8;
  350. /// <summary>
  351. /// Chroma Key Color
  352. /// </summary>
  353. [HideInInspector, Tooltip("Chroma Key Color")]
  354. public Color chromaKeyColor = Color.green;
  355. /// <summary>
  356. /// Chroma Key Similarity
  357. /// </summary>
  358. [HideInInspector, Tooltip("Chroma Key Similarity")]
  359. public float chromaKeySimilarity = 0.60f;
  360. /// <summary>
  361. /// Chroma Key Smooth Range
  362. /// </summary>
  363. [HideInInspector, Tooltip("Chroma Key Smooth Range")]
  364. public float chromaKeySmoothRange = 0.03f;
  365. /// <summary>
  366. /// Chroma Key Spill Range
  367. /// </summary>
  368. [HideInInspector, Tooltip("Chroma Key Spill Range")]
  369. public float chromaKeySpillRange = 0.06f;
  370. /// <summary>
  371. /// Use dynamic lighting (Depth sensor required)
  372. /// </summary>
  373. [HideInInspector, Tooltip("Use dynamic lighting (Depth sensor required)")]
  374. public bool useDynamicLighting = false;
  375. public enum DepthQuality
  376. {
  377. Low,
  378. Medium,
  379. High
  380. }
  381. /// <summary>
  382. /// The quality level of depth image. The lighting could be more smooth and accurate with high quality depth, but it would also be more costly in performance.
  383. /// </summary>
  384. [HideInInspector, Tooltip("The quality level of depth image. The lighting could be more smooth and accurate with high quality depth, but it would also be more costly in performance.")]
  385. public DepthQuality depthQuality = DepthQuality.Medium;
  386. /// <summary>
  387. /// Smooth factor in dynamic lighting. Larger is smoother
  388. /// </summary>
  389. [HideInInspector, Tooltip("Smooth factor in dynamic lighting. Larger is smoother")]
  390. public float dynamicLightingSmoothFactor = 8.0f;
  391. /// <summary>
  392. /// The maximum depth variation across the edges. Make it smaller to smooth the lighting on the edges.
  393. /// </summary>
  394. [HideInInspector, Tooltip("The maximum depth variation across the edges. Make it smaller to smooth the lighting on the edges.")]
  395. public float dynamicLightingDepthVariationClampingValue = 0.001f;
  396. public enum VirtualGreenScreenType
  397. {
  398. Off,
  399. OuterBoundary,
  400. PlayArea
  401. }
  402. /// <summary>
  403. /// Set the current type of the virtual green screen
  404. /// </summary>
  405. [HideInInspector, Tooltip("Type of virutal green screen ")]
  406. public VirtualGreenScreenType virtualGreenScreenType = VirtualGreenScreenType.Off;
  407. /// <summary>
  408. /// Top Y of virtual screen
  409. /// </summary>
  410. [HideInInspector, Tooltip("Top Y of virtual green screen")]
  411. public float virtualGreenScreenTopY = 10.0f;
  412. /// <summary>
  413. /// Bottom Y of virtual screen
  414. /// </summary>
  415. [HideInInspector, Tooltip("Bottom Y of virtual green screen")]
  416. public float virtualGreenScreenBottomY = -10.0f;
  417. /// <summary>
  418. /// When using a depth camera (e.g. ZED), whether to use the depth in virtual green screen culling.
  419. /// </summary>
  420. [HideInInspector, Tooltip("When using a depth camera (e.g. ZED), whether to use the depth in virtual green screen culling.")]
  421. public bool virtualGreenScreenApplyDepthCulling = false;
  422. /// <summary>
  423. /// The tolerance value (in meter) when using the virtual green screen with a depth camera. Make it bigger if the foreground objects got culled incorrectly.
  424. /// </summary>
  425. [HideInInspector, Tooltip("The tolerance value (in meter) when using the virtual green screen with a depth camera. Make it bigger if the foreground objects got culled incorrectly.")]
  426. public float virtualGreenScreenDepthTolerance = 0.2f;
  427. #endif
  428. /// <summary>
  429. /// The number of expected display frames per rendered frame.
  430. /// </summary>
  431. public int vsyncCount
  432. {
  433. get {
  434. if (!isHmdPresent)
  435. return 1;
  436. return OVRPlugin.vsyncCount;
  437. }
  438. set {
  439. if (!isHmdPresent)
  440. return;
  441. OVRPlugin.vsyncCount = value;
  442. }
  443. }
  444. /// <summary>
  445. /// Gets the current battery level.
  446. /// </summary>
  447. /// <returns><c>battery level in the range [0.0,1.0]</c>
  448. /// <param name="batteryLevel">Battery level.</param>
  449. public static float batteryLevel
  450. {
  451. get {
  452. if (!isHmdPresent)
  453. return 1f;
  454. return OVRPlugin.batteryLevel;
  455. }
  456. }
  457. /// <summary>
  458. /// Gets the current battery temperature.
  459. /// </summary>
  460. /// <returns><c>battery temperature in Celsius</c>
  461. /// <param name="batteryTemperature">Battery temperature.</param>
  462. public static float batteryTemperature
  463. {
  464. get {
  465. if (!isHmdPresent)
  466. return 0f;
  467. return OVRPlugin.batteryTemperature;
  468. }
  469. }
  470. /// <summary>
  471. /// Gets the current battery status.
  472. /// </summary>
  473. /// <returns><c>battery status</c>
  474. /// <param name="batteryStatus">Battery status.</param>
  475. public static int batteryStatus
  476. {
  477. get {
  478. if (!isHmdPresent)
  479. return -1;
  480. return (int)OVRPlugin.batteryStatus;
  481. }
  482. }
  483. /// <summary>
  484. /// Gets the current volume level.
  485. /// </summary>
  486. /// <returns><c>volume level in the range [0,1].</c>
  487. public static float volumeLevel
  488. {
  489. get {
  490. if (!isHmdPresent)
  491. return 0f;
  492. return OVRPlugin.systemVolume;
  493. }
  494. }
  495. /// <summary>
  496. /// Gets or sets the current CPU performance level (0-2). Lower performance levels save more power.
  497. /// </summary>
  498. public static int cpuLevel
  499. {
  500. get {
  501. if (!isHmdPresent)
  502. return 2;
  503. return OVRPlugin.cpuLevel;
  504. }
  505. set {
  506. if (!isHmdPresent)
  507. return;
  508. OVRPlugin.cpuLevel = value;
  509. }
  510. }
  511. /// <summary>
  512. /// Gets or sets the current GPU performance level (0-2). Lower performance levels save more power.
  513. /// </summary>
  514. public static int gpuLevel
  515. {
  516. get {
  517. if (!isHmdPresent)
  518. return 2;
  519. return OVRPlugin.gpuLevel;
  520. }
  521. set {
  522. if (!isHmdPresent)
  523. return;
  524. OVRPlugin.gpuLevel = value;
  525. }
  526. }
  527. /// <summary>
  528. /// If true, the CPU and GPU are currently throttled to save power and/or reduce the temperature.
  529. /// </summary>
  530. public static bool isPowerSavingActive
  531. {
  532. get {
  533. if (!isHmdPresent)
  534. return false;
  535. return OVRPlugin.powerSaving;
  536. }
  537. }
  538. /// <summary>
  539. /// Gets or sets the eye texture format.
  540. /// </summary>
  541. public static EyeTextureFormat eyeTextureFormat
  542. {
  543. get
  544. {
  545. return (OVRManager.EyeTextureFormat)OVRPlugin.GetDesiredEyeTextureFormat();
  546. }
  547. set
  548. {
  549. OVRPlugin.SetDesiredEyeTextureFormat((OVRPlugin.EyeTextureFormat)value);
  550. }
  551. }
  552. /// <summary>
  553. /// Gets if tiled-based multi-resolution technique is supported
  554. /// This feature is only supported on QCOMM-based Android devices
  555. /// </summary>
  556. public static bool tiledMultiResSupported
  557. {
  558. get
  559. {
  560. return OVRPlugin.tiledMultiResSupported;
  561. }
  562. }
  563. /// <summary>
  564. /// Gets or sets the tiled-based multi-resolution level
  565. /// This feature is only supported on QCOMM-based Android devices
  566. /// </summary>
  567. public static TiledMultiResLevel tiledMultiResLevel
  568. {
  569. get
  570. {
  571. if (!OVRPlugin.tiledMultiResSupported)
  572. {
  573. Debug.LogWarning("Tiled-based Multi-resolution feature is not supported");
  574. }
  575. return (TiledMultiResLevel)OVRPlugin.tiledMultiResLevel;
  576. }
  577. set
  578. {
  579. if (!OVRPlugin.tiledMultiResSupported)
  580. {
  581. Debug.LogWarning("Tiled-based Multi-resolution feature is not supported");
  582. }
  583. OVRPlugin.tiledMultiResLevel = (OVRPlugin.TiledMultiResLevel)value;
  584. }
  585. }
  586. /// <summary>
  587. /// Gets if the GPU Utility is supported
  588. /// This feature is only supported on QCOMM-based Android devices
  589. /// </summary>
  590. public static bool gpuUtilSupported
  591. {
  592. get
  593. {
  594. return OVRPlugin.gpuUtilSupported;
  595. }
  596. }
  597. /// <summary>
  598. /// Gets the GPU Utilised Level (0.0 - 1.0)
  599. /// This feature is only supported on QCOMM-based Android devices
  600. /// </summary>
  601. public static float gpuUtilLevel
  602. {
  603. get
  604. {
  605. if (!OVRPlugin.gpuUtilSupported)
  606. {
  607. Debug.LogWarning("GPU Util is not supported");
  608. }
  609. return OVRPlugin.gpuUtilLevel;
  610. }
  611. }
  612. [Header("Tracking")]
  613. [SerializeField]
  614. [Tooltip("Defines the current tracking origin type.")]
  615. private OVRManager.TrackingOrigin _trackingOriginType = OVRManager.TrackingOrigin.EyeLevel;
  616. /// <summary>
  617. /// Defines the current tracking origin type.
  618. /// </summary>
  619. public OVRManager.TrackingOrigin trackingOriginType
  620. {
  621. get {
  622. if (!isHmdPresent)
  623. return _trackingOriginType;
  624. return (OVRManager.TrackingOrigin)OVRPlugin.GetTrackingOriginType();
  625. }
  626. set {
  627. if (!isHmdPresent)
  628. return;
  629. if (OVRPlugin.SetTrackingOriginType((OVRPlugin.TrackingOrigin)value))
  630. {
  631. // Keep the field exposed in the Unity Editor synchronized with any changes.
  632. _trackingOriginType = value;
  633. }
  634. }
  635. }
  636. /// <summary>
  637. /// If true, head tracking will affect the position of each OVRCameraRig's cameras.
  638. /// </summary>
  639. [Tooltip("If true, head tracking will affect the position of each OVRCameraRig's cameras.")]
  640. public bool usePositionTracking = true;
  641. /// <summary>
  642. /// If true, head tracking will affect the rotation of each OVRCameraRig's cameras.
  643. /// </summary>
  644. [HideInInspector]
  645. public bool useRotationTracking = true;
  646. /// <summary>
  647. /// If true, the distance between the user's eyes will affect the position of each OVRCameraRig's cameras.
  648. /// </summary>
  649. [Tooltip("If true, the distance between the user's eyes will affect the position of each OVRCameraRig's cameras.")]
  650. public bool useIPDInPositionTracking = true;
  651. /// <summary>
  652. /// If true, each scene load will cause the head pose to reset.
  653. /// </summary>
  654. [Tooltip("If true, each scene load will cause the head pose to reset.")]
  655. public bool resetTrackerOnLoad = false;
  656. /// <summary>
  657. /// If true, the Reset View in the universal menu will cause the pose to be reset. This should generally be
  658. /// enabled for applications with a stationary position in the virtual world and will allow the View Reset
  659. /// command to place the person back to a predefined location (such as a cockpit seat).
  660. /// Set this to false if you have a locomotion system because resetting the view would effectively teleport
  661. /// the player to potentially invalid locations.
  662. /// </summary>
  663. [Tooltip("If true, the Reset View in the universal menu will cause the pose to be reset. This should generally be enabled for applications with a stationary position in the virtual world and will allow the View Reset command to place the person back to a predefined location (such as a cockpit seat). Set this to false if you have a locomotion system because resetting the view would effectively teleport the player to potentially invalid locations.")]
  664. public bool AllowRecenter = true;
  665. /// <summary>
  666. /// True if the current platform supports virtual reality.
  667. /// </summary>
  668. public bool isSupportedPlatform { get; private set; }
  669. private static bool _isUserPresentCached = false;
  670. private static bool _isUserPresent = false;
  671. private static bool _wasUserPresent = false;
  672. /// <summary>
  673. /// True if the user is currently wearing the display.
  674. /// </summary>
  675. public bool isUserPresent
  676. {
  677. get {
  678. if (!_isUserPresentCached)
  679. {
  680. _isUserPresentCached = true;
  681. _isUserPresent = OVRPlugin.userPresent;
  682. }
  683. return _isUserPresent;
  684. }
  685. private set {
  686. _isUserPresentCached = true;
  687. _isUserPresent = value;
  688. }
  689. }
  690. private static bool prevAudioOutIdIsCached = false;
  691. private static bool prevAudioInIdIsCached = false;
  692. private static string prevAudioOutId = string.Empty;
  693. private static string prevAudioInId = string.Empty;
  694. private static bool wasPositionTracked = false;
  695. public static System.Version utilitiesVersion
  696. {
  697. get { return OVRPlugin.wrapperVersion; }
  698. }
  699. public static System.Version pluginVersion
  700. {
  701. get { return OVRPlugin.version; }
  702. }
  703. public static System.Version sdkVersion
  704. {
  705. get { return OVRPlugin.nativeSDKVersion; }
  706. }
  707. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  708. private static bool prevEnableMixedReality = false;
  709. private static bool MixedRealityEnabledFromCmd()
  710. {
  711. var args = System.Environment.GetCommandLineArgs();
  712. for (int i = 0; i < args.Length; i++)
  713. {
  714. if (args[i].ToLower() == "-mixedreality")
  715. return true;
  716. }
  717. return false;
  718. }
  719. private static bool UseDirectCompositionFromCmd()
  720. {
  721. var args = System.Environment.GetCommandLineArgs();
  722. for (int i = 0; i < args.Length; i++)
  723. {
  724. if (args[i].ToLower() == "-directcomposition")
  725. return true;
  726. }
  727. return false;
  728. }
  729. private static bool UseExternalCompositionFromCmd()
  730. {
  731. var args = System.Environment.GetCommandLineArgs();
  732. for (int i = 0; i < args.Length; i++)
  733. {
  734. if (args[i].ToLower() == "-externalcomposition")
  735. return true;
  736. }
  737. return false;
  738. }
  739. private static bool CreateMixedRealityCaptureConfigurationFileFromCmd()
  740. {
  741. var args = System.Environment.GetCommandLineArgs();
  742. for (int i = 0; i < args.Length; i++)
  743. {
  744. if (args[i].ToLower() == "-create_mrc_config")
  745. return true;
  746. }
  747. return false;
  748. }
  749. private static bool LoadMixedRealityCaptureConfigurationFileFromCmd()
  750. {
  751. var args = System.Environment.GetCommandLineArgs();
  752. for (int i = 0; i < args.Length; i++)
  753. {
  754. if (args[i].ToLower() == "-load_mrc_config")
  755. return true;
  756. }
  757. return false;
  758. }
  759. #endif
  760. #region Unity Messages
  761. private void Awake()
  762. {
  763. // Only allow one instance at runtime.
  764. if (instance != null)
  765. {
  766. enabled = false;
  767. DestroyImmediate(this);
  768. return;
  769. }
  770. instance = this;
  771. Debug.Log("Unity v" + Application.unityVersion + ", " +
  772. "Oculus Utilities v" + OVRPlugin.wrapperVersion + ", " +
  773. "OVRPlugin v" + OVRPlugin.version + ", " +
  774. "SDK v" + OVRPlugin.nativeSDKVersion + ".");
  775. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  776. var supportedTypes =
  777. UnityEngine.Rendering.GraphicsDeviceType.Direct3D11.ToString() + ", " +
  778. UnityEngine.Rendering.GraphicsDeviceType.Direct3D12.ToString();
  779. if (!supportedTypes.Contains(SystemInfo.graphicsDeviceType.ToString()))
  780. Debug.LogWarning("VR rendering requires one of the following device types: (" + supportedTypes + "). Your graphics device: " + SystemInfo.graphicsDeviceType.ToString());
  781. #endif
  782. // Detect whether this platform is a supported platform
  783. RuntimePlatform currPlatform = Application.platform;
  784. isSupportedPlatform |= currPlatform == RuntimePlatform.Android;
  785. //isSupportedPlatform |= currPlatform == RuntimePlatform.LinuxPlayer;
  786. isSupportedPlatform |= currPlatform == RuntimePlatform.OSXEditor;
  787. isSupportedPlatform |= currPlatform == RuntimePlatform.OSXPlayer;
  788. isSupportedPlatform |= currPlatform == RuntimePlatform.WindowsEditor;
  789. isSupportedPlatform |= currPlatform == RuntimePlatform.WindowsPlayer;
  790. if (!isSupportedPlatform)
  791. {
  792. Debug.LogWarning("This platform is unsupported");
  793. return;
  794. }
  795. #if UNITY_ANDROID && !UNITY_EDITOR
  796. // Turn off chromatic aberration by default to save texture bandwidth.
  797. chromatic = false;
  798. #endif
  799. #if UNITY_STANDALONE_WIN && !UNITY_EDITOR
  800. enableMixedReality = false; // we should never start the standalone game in MxR mode, unless the command-line parameter is provided
  801. #endif
  802. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  803. bool loadMrcConfig = LoadMixedRealityCaptureConfigurationFileFromCmd();
  804. bool createMrcConfig = CreateMixedRealityCaptureConfigurationFileFromCmd();
  805. if (loadMrcConfig || createMrcConfig)
  806. {
  807. OVRMixedRealityCaptureSettings mrcSettings = ScriptableObject.CreateInstance<OVRMixedRealityCaptureSettings>();
  808. mrcSettings.ReadFrom(this);
  809. if (loadMrcConfig)
  810. {
  811. mrcSettings.CombineWithConfigurationFile();
  812. mrcSettings.ApplyTo(this);
  813. }
  814. if (createMrcConfig)
  815. {
  816. mrcSettings.WriteToConfigurationFile();
  817. }
  818. ScriptableObject.Destroy(mrcSettings);
  819. }
  820. if (MixedRealityEnabledFromCmd())
  821. {
  822. enableMixedReality = true;
  823. }
  824. if (enableMixedReality)
  825. {
  826. Debug.Log("OVR: Mixed Reality mode enabled");
  827. if (UseDirectCompositionFromCmd())
  828. {
  829. compositionMethod = CompositionMethod.Direct;
  830. }
  831. if (UseExternalCompositionFromCmd())
  832. {
  833. compositionMethod = CompositionMethod.External;
  834. }
  835. Debug.Log("OVR: CompositionMethod : " + compositionMethod);
  836. }
  837. #endif
  838. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  839. if (enableAdaptiveResolution && !OVRManager.IsAdaptiveResSupportedByEngine())
  840. {
  841. enableAdaptiveResolution = false;
  842. UnityEngine.Debug.LogError("Your current Unity Engine " + Application.unityVersion + " might have issues to support adaptive resolution, please disable it under OVRManager");
  843. }
  844. #endif
  845. Initialize();
  846. if (resetTrackerOnLoad)
  847. display.RecenterPose();
  848. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  849. // Force OcculusionMesh on all the time, you can change the value to false if you really need it be off for some reasons,
  850. // be aware there are performance drops if you don't use occlusionMesh.
  851. OVRPlugin.occlusionMesh = true;
  852. #endif
  853. }
  854. #if UNITY_EDITOR
  855. private static bool _scriptsReloaded;
  856. [UnityEditor.Callbacks.DidReloadScripts]
  857. static void ScriptsReloaded()
  858. {
  859. _scriptsReloaded = true;
  860. }
  861. #endif
  862. void Initialize()
  863. {
  864. if (display == null)
  865. display = new OVRDisplay();
  866. if (tracker == null)
  867. tracker = new OVRTracker();
  868. if (boundary == null)
  869. boundary = new OVRBoundary();
  870. }
  871. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  872. private bool suppressDisableMixedRealityBecauseOfNoMainCameraWarning = false;
  873. #endif
  874. private void Update()
  875. {
  876. #if UNITY_EDITOR
  877. if (_scriptsReloaded)
  878. {
  879. _scriptsReloaded = false;
  880. instance = this;
  881. Initialize();
  882. }
  883. #endif
  884. if (OVRPlugin.shouldQuit)
  885. Application.Quit();
  886. if (AllowRecenter && OVRPlugin.shouldRecenter)
  887. {
  888. OVRManager.display.RecenterPose();
  889. }
  890. if (trackingOriginType != _trackingOriginType)
  891. trackingOriginType = _trackingOriginType;
  892. tracker.isEnabled = usePositionTracking;
  893. OVRPlugin.rotation = useRotationTracking;
  894. OVRPlugin.useIPDInPositionTracking = useIPDInPositionTracking;
  895. // Dispatch HMD events.
  896. isHmdPresent = OVRPlugin.hmdPresent;
  897. if (useRecommendedMSAALevel && QualitySettings.antiAliasing != display.recommendedMSAALevel)
  898. {
  899. Debug.Log("The current MSAA level is " + QualitySettings.antiAliasing +
  900. ", but the recommended MSAA level is " + display.recommendedMSAALevel +
  901. ". Switching to the recommended level.");
  902. QualitySettings.antiAliasing = display.recommendedMSAALevel;
  903. }
  904. if (monoscopic != _monoscopic)
  905. {
  906. monoscopic = _monoscopic;
  907. }
  908. if (_wasHmdPresent && !isHmdPresent)
  909. {
  910. try
  911. {
  912. if (HMDLost != null)
  913. HMDLost();
  914. }
  915. catch (Exception e)
  916. {
  917. Debug.LogError("Caught Exception: " + e);
  918. }
  919. }
  920. if (!_wasHmdPresent && isHmdPresent)
  921. {
  922. try
  923. {
  924. if (HMDAcquired != null)
  925. HMDAcquired();
  926. }
  927. catch (Exception e)
  928. {
  929. Debug.LogError("Caught Exception: " + e);
  930. }
  931. }
  932. _wasHmdPresent = isHmdPresent;
  933. // Dispatch HMD mounted events.
  934. isUserPresent = OVRPlugin.userPresent;
  935. if (_wasUserPresent && !isUserPresent)
  936. {
  937. try
  938. {
  939. if (HMDUnmounted != null)
  940. HMDUnmounted();
  941. }
  942. catch (Exception e)
  943. {
  944. Debug.LogError("Caught Exception: " + e);
  945. }
  946. }
  947. if (!_wasUserPresent && isUserPresent)
  948. {
  949. try
  950. {
  951. if (HMDMounted != null)
  952. HMDMounted();
  953. }
  954. catch (Exception e)
  955. {
  956. Debug.LogError("Caught Exception: " + e);
  957. }
  958. }
  959. _wasUserPresent = isUserPresent;
  960. // Dispatch VR Focus events.
  961. hasVrFocus = OVRPlugin.hasVrFocus;
  962. if (_hadVrFocus && !hasVrFocus)
  963. {
  964. try
  965. {
  966. if (VrFocusLost != null)
  967. VrFocusLost();
  968. }
  969. catch (Exception e)
  970. {
  971. Debug.LogError("Caught Exception: " + e);
  972. }
  973. }
  974. if (!_hadVrFocus && hasVrFocus)
  975. {
  976. try
  977. {
  978. if (VrFocusAcquired != null)
  979. VrFocusAcquired();
  980. }
  981. catch (Exception e)
  982. {
  983. Debug.LogError("Caught Exception: " + e);
  984. }
  985. }
  986. _hadVrFocus = hasVrFocus;
  987. // Dispatch VR Input events.
  988. bool hasInputFocus = OVRPlugin.hasInputFocus;
  989. if (_hadInputFocus && !hasInputFocus)
  990. {
  991. try
  992. {
  993. if (InputFocusLost != null)
  994. InputFocusLost();
  995. }
  996. catch (Exception e)
  997. {
  998. Debug.LogError("Caught Exception: " + e);
  999. }
  1000. }
  1001. if (!_hadInputFocus && hasInputFocus)
  1002. {
  1003. try
  1004. {
  1005. if (InputFocusAcquired != null)
  1006. InputFocusAcquired();
  1007. }
  1008. catch (Exception e)
  1009. {
  1010. Debug.LogError("Caught Exception: " + e);
  1011. }
  1012. }
  1013. _hadInputFocus = hasInputFocus;
  1014. // Changing effective rendering resolution dynamically according performance
  1015. #if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
  1016. if (enableAdaptiveResolution)
  1017. {
  1018. #if UNITY_2017_2_OR_NEWER
  1019. if (UnityEngine.XR.XRSettings.eyeTextureResolutionScale < maxRenderScale)
  1020. {
  1021. // Allocate renderScale to max to avoid re-allocation
  1022. UnityEngine.XR.XRSettings.eyeTextureResolutionScale = maxRenderScale;
  1023. }
  1024. else
  1025. {
  1026. // Adjusting maxRenderScale in case app started with a larger renderScale value
  1027. maxRenderScale = Mathf.Max(maxRenderScale, UnityEngine.XR.XRSettings.eyeTextureResolutionScale);
  1028. }
  1029. minRenderScale = Mathf.Min(minRenderScale, maxRenderScale);
  1030. float minViewportScale = minRenderScale / UnityEngine.XR.XRSettings.eyeTextureResolutionScale;
  1031. float recommendedViewportScale = OVRPlugin.GetEyeRecommendedResolutionScale() / UnityEngine.XR.XRSettings.eyeTextureResolutionScale;
  1032. recommendedViewportScale = Mathf.Clamp(recommendedViewportScale, minViewportScale, 1.0f);
  1033. UnityEngine.XR.XRSettings.renderViewportScale = recommendedViewportScale;
  1034. #else
  1035. if (UnityEngine.VR.VRSettings.renderScale < maxRenderScale)
  1036. {
  1037. // Allocate renderScale to max to avoid re-allocation
  1038. UnityEngine.VR.VRSettings.renderScale = maxRenderScale;
  1039. }
  1040. else
  1041. {
  1042. // Adjusting maxRenderScale in case app started with a larger renderScale value
  1043. maxRenderScale = Mathf.Max(maxRenderScale, UnityEngine.VR.VRSettings.renderScale);
  1044. }
  1045. minRenderScale = Mathf.Min(minRenderScale, maxRenderScale);
  1046. float minViewportScale = minRenderScale / UnityEngine.VR.VRSettings.renderScale;
  1047. float recommendedViewportScale = OVRPlugin.GetEyeRecommendedResolutionScale() / UnityEngine.VR.VRSettings.renderScale;
  1048. recommendedViewportScale = Mathf.Clamp(recommendedViewportScale, minViewportScale, 1.0f);
  1049. UnityEngine.VR.VRSettings.renderViewportScale = recommendedViewportScale;
  1050. #endif
  1051. }
  1052. #endif
  1053. // Dispatch Audio Device events.
  1054. string audioOutId = OVRPlugin.audioOutId;
  1055. if (!prevAudioOutIdIsCached)
  1056. {
  1057. prevAudioOutId = audioOutId;
  1058. prevAudioOutIdIsCached = true;
  1059. }
  1060. else if (audioOutId != prevAudioOutId)
  1061. {
  1062. try
  1063. {
  1064. if (AudioOutChanged != null)
  1065. AudioOutChanged();
  1066. }
  1067. catch (Exception e)
  1068. {
  1069. Debug.LogError("Caught Exception: " + e);
  1070. }
  1071. prevAudioOutId = audioOutId;
  1072. }
  1073. string audioInId = OVRPlugin.audioInId;
  1074. if (!prevAudioInIdIsCached)
  1075. {
  1076. prevAudioInId = audioInId;
  1077. prevAudioInIdIsCached = true;
  1078. }
  1079. else if (audioInId != prevAudioInId)
  1080. {
  1081. try
  1082. {
  1083. if (AudioInChanged != null)
  1084. AudioInChanged();
  1085. }
  1086. catch (Exception e)
  1087. {
  1088. Debug.LogError("Caught Exception: " + e);
  1089. }
  1090. prevAudioInId = audioInId;
  1091. }
  1092. // Dispatch tracking events.
  1093. if (wasPositionTracked && !tracker.isPositionTracked)
  1094. {
  1095. try
  1096. {
  1097. if (TrackingLost != null)
  1098. TrackingLost();
  1099. }
  1100. catch (Exception e)
  1101. {
  1102. Debug.LogError("Caught Exception: " + e);
  1103. }
  1104. }
  1105. if (!wasPositionTracked && tracker.isPositionTracked)
  1106. {
  1107. try
  1108. {
  1109. if (TrackingAcquired != null)
  1110. TrackingAcquired();
  1111. }
  1112. catch (Exception e)
  1113. {
  1114. Debug.LogError("Caught Exception: " + e);
  1115. }
  1116. }
  1117. wasPositionTracked = tracker.isPositionTracked;
  1118. display.Update();
  1119. OVRInput.Update();
  1120. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  1121. if (enableMixedReality || prevEnableMixedReality)
  1122. {
  1123. Camera mainCamera = FindMainCamera();
  1124. if (Camera.main != null)
  1125. {
  1126. suppressDisableMixedRealityBecauseOfNoMainCameraWarning = false;
  1127. if (enableMixedReality)
  1128. {
  1129. OVRMixedReality.Update(this.gameObject, mainCamera, compositionMethod, useDynamicLighting, capturingCameraDevice, depthQuality);
  1130. }
  1131. if (prevEnableMixedReality && !enableMixedReality)
  1132. {
  1133. OVRMixedReality.Cleanup();
  1134. }
  1135. prevEnableMixedReality = enableMixedReality;
  1136. }
  1137. else
  1138. {
  1139. if (!suppressDisableMixedRealityBecauseOfNoMainCameraWarning)
  1140. {
  1141. Debug.LogWarning("Main Camera is not set, Mixed Reality disabled");
  1142. suppressDisableMixedRealityBecauseOfNoMainCameraWarning = true;
  1143. }
  1144. }
  1145. }
  1146. #endif
  1147. }
  1148. private bool multipleMainCameraWarningPresented = false;
  1149. private Camera FindMainCamera()
  1150. {
  1151. GameObject[] objects = GameObject.FindGameObjectsWithTag("MainCamera");
  1152. List<Camera> cameras = new List<Camera>(4);
  1153. foreach (GameObject obj in objects)
  1154. {
  1155. Camera camera = obj.GetComponent<Camera>();
  1156. if (camera != null && camera.enabled)
  1157. {
  1158. OVRCameraRig cameraRig = camera.GetComponentInParent<OVRCameraRig>();
  1159. if (cameraRig != null && cameraRig.trackingSpace != null)
  1160. {
  1161. cameras.Add(camera);
  1162. }
  1163. }
  1164. }
  1165. if (cameras.Count == 0)
  1166. {
  1167. return Camera.main; // pick one of the cameras which tagged as "MainCamera"
  1168. }
  1169. else if (cameras.Count == 1)
  1170. {
  1171. return cameras[0];
  1172. }
  1173. else
  1174. {
  1175. if (!multipleMainCameraWarningPresented)
  1176. {
  1177. Debug.LogWarning("Multiple MainCamera found. Assume the real MainCamera is the camera with the least depth");
  1178. multipleMainCameraWarningPresented = true;
  1179. }
  1180. // return the camera with least depth
  1181. cameras.Sort((Camera c0, Camera c1) => { return c0.depth < c1.depth ? -1 : (c0.depth > c1.depth ? 1 : 0); });
  1182. return cameras[0];
  1183. }
  1184. }
  1185. private void OnDisable()
  1186. {
  1187. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  1188. OVRMixedReality.Cleanup();
  1189. #endif
  1190. }
  1191. private void LateUpdate()
  1192. {
  1193. OVRHaptics.Process();
  1194. }
  1195. private void FixedUpdate()
  1196. {
  1197. OVRInput.FixedUpdate();
  1198. }
  1199. /// <summary>
  1200. /// Leaves the application/game and returns to the launcher/dashboard
  1201. /// </summary>
  1202. public void ReturnToLauncher()
  1203. {
  1204. // show the platform UI quit prompt
  1205. OVRManager.PlatformUIConfirmQuit();
  1206. }
  1207. #endregion
  1208. public static void PlatformUIConfirmQuit()
  1209. {
  1210. if (!isHmdPresent)
  1211. return;
  1212. OVRPlugin.ShowUI(OVRPlugin.PlatformUI.ConfirmQuit);
  1213. }
  1214. }