UpdateMultiPassStereo.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #if UNITY_ANDROID
  2. #if USING_URP
  3. #define ANDROID_URP
  4. #endif
  5. #endif
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. using UnityEngine.Rendering;
  9. //-----------------------------------------------------------------------------
  10. // Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
  11. //-----------------------------------------------------------------------------
  12. namespace RenderHeads.Media.AVProVideo
  13. {
  14. /// <summary>
  15. /// This script is needed to send the camera position to the stereo shader so that
  16. /// it can determine which eye it is rendering. This is only needed for multi-pass
  17. /// rendering, as single pass has a built-in shader variable
  18. /// </summary>
  19. [AddComponentMenu("AVPro Video/Update Multi-Pass Stereo", 320)]
  20. [HelpURL("https://www.renderheads.com/products/avpro-video/")]
  21. public class UpdateMultiPassStereo : MonoBehaviour
  22. {
  23. [Header("Stereo camera")]
  24. [SerializeField] Camera _camera = null;
  25. public Camera Camera
  26. {
  27. get { return _camera; }
  28. set { _camera = value; }
  29. }
  30. private static readonly LazyShaderProperty PropWorldCameraPosition = new LazyShaderProperty("_WorldCameraPosition");
  31. private static readonly LazyShaderProperty PropWorldCameraRight = new LazyShaderProperty("_WorldCameraRight");
  32. // State
  33. private Camera _foundCamera;
  34. void Awake()
  35. {
  36. if (_camera == null)
  37. {
  38. Debug.LogWarning("[AVProVideo] No camera set for UpdateMultiPassStereo component. If you are rendering in multi-pass stereo then it is recommended to set this.");
  39. }
  40. }
  41. void Start()
  42. {
  43. LogXRDeviceDetails();
  44. #if ANDROID_URP
  45. if( GetComponent<Camera>() == null )
  46. {
  47. throw new MissingComponentException("[AVProVideo] When using URP the UpdateMultiPassStereo component must be on the Camera gameobject. This component is not required on all VR devices, but if it is then stereo eye rendering may not work correctly.");
  48. }
  49. #endif
  50. }
  51. private void LogXRDeviceDetails()
  52. {
  53. #if UNITY_2019_1_OR_NEWER && !UNITY_TVOS
  54. string logOutput = "[AVProVideo] XR Device details: UnityEngine.XR.XRSettings.loadedDeviceName = " + UnityEngine.XR.XRSettings.loadedDeviceName + " | supportedDevices = ";
  55. string[] aSupportedDevices = UnityEngine.XR.XRSettings.supportedDevices;
  56. int supportedDeviceCount = aSupportedDevices.Length;
  57. for (int i = 0; i < supportedDeviceCount; i++)
  58. {
  59. logOutput += aSupportedDevices[i];
  60. if( i < (supportedDeviceCount - 1 ))
  61. {
  62. logOutput += ", ";
  63. }
  64. }
  65. List<UnityEngine.XR.InputDevice> inputDevices = new List<UnityEngine.XR.InputDevice>();
  66. UnityEngine.XR.InputDevices.GetDevices(inputDevices);
  67. int deviceCount = inputDevices.Count;
  68. if (deviceCount > 0)
  69. {
  70. logOutput += " | XR Devices = ";
  71. for (int i = 0; i < deviceCount; i++)
  72. {
  73. logOutput += inputDevices[i].name;
  74. if( i < (deviceCount -1 ))
  75. {
  76. logOutput += ", ";
  77. }
  78. }
  79. }
  80. UnityEngine.XR.InputDevice headDevice = UnityEngine.XR.InputDevices.GetDeviceAtXRNode(UnityEngine.XR.XRNode.Head);
  81. if( headDevice != null )
  82. {
  83. logOutput += " | headDevice name = " + headDevice.name + ", manufacturer = " + headDevice.manufacturer;
  84. }
  85. Debug.Log(logOutput);
  86. #endif
  87. }
  88. #if ANDROID_URP
  89. void OnEnable()
  90. {
  91. RenderPipelineManager.beginCameraRendering += RenderPipelineManager_beginCameraRendering;
  92. }
  93. void OnDisable()
  94. {
  95. RenderPipelineManager.beginCameraRendering -= RenderPipelineManager_beginCameraRendering;
  96. }
  97. #endif
  98. private static bool IsMultiPassVrEnabled()
  99. {
  100. #if UNITY_TVOS
  101. return false;
  102. #else
  103. #if UNITY_2017_2_OR_NEWER
  104. if (!UnityEngine.XR.XRSettings.enabled) return false;
  105. #endif
  106. #if UNITY_2018_3_OR_NEWER
  107. if (UnityEngine.XR.XRSettings.stereoRenderingMode != UnityEngine.XR.XRSettings.StereoRenderingMode.MultiPass) return false;
  108. #endif
  109. return true;
  110. #endif
  111. }
  112. // We do a LateUpdate() to allow for any changes in the camera position that may have happened in Update()
  113. #if ANDROID_URP
  114. // Android URP
  115. private void RenderPipelineManager_beginCameraRendering(ScriptableRenderContext context, Camera camera)
  116. #else
  117. // Normal render pipeline
  118. private void LateUpdate()
  119. #endif
  120. {
  121. if (!IsMultiPassVrEnabled())
  122. {
  123. return;
  124. }
  125. if (_camera != null && _foundCamera != _camera)
  126. {
  127. _foundCamera = _camera;
  128. }
  129. if (_foundCamera == null)
  130. {
  131. _foundCamera = Camera.main;
  132. if (_foundCamera == null)
  133. {
  134. Debug.LogWarning("[AVProVideo] Cannot find main camera for UpdateMultiPassStereo, this can lead to eyes flickering");
  135. if (Camera.allCameras.Length > 0)
  136. {
  137. _foundCamera = Camera.allCameras[0];
  138. Debug.LogWarning("[AVProVideo] UpdateMultiPassStereo using camera " + _foundCamera.name);
  139. }
  140. }
  141. }
  142. if (_foundCamera != null)
  143. {
  144. Shader.SetGlobalVector(PropWorldCameraPosition.Id, _foundCamera.transform.position);
  145. Shader.SetGlobalVector(PropWorldCameraRight.Id, _foundCamera.transform.right);
  146. }
  147. }
  148. }
  149. }