CameraSelector.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. using UnityEngine;
  2. using UnityEngine.SceneManagement;
  3. //-----------------------------------------------------------------------------
  4. // Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
  5. //-----------------------------------------------------------------------------
  6. namespace RenderHeads.Media.AVProMovieCapture
  7. {
  8. /// <summary>
  9. /// Selects the camera to use for captures based on various factors
  10. /// TODO: add support for persisting across scene changes
  11. /// </summary>
  12. [AddComponentMenu("AVPro Movie Capture/Utils/Camera Selector", 300)]
  13. public class CameraSelector : MonoBehaviour
  14. {
  15. public enum SelectByMode
  16. {
  17. HighestDepthCamera,
  18. MainCameraTag,
  19. EditorSceneView,
  20. Tag,
  21. Name,
  22. Manual,
  23. }
  24. public enum ScanFrequencyMode
  25. {
  26. Manual,
  27. SceneLoad,
  28. Frame,
  29. }
  30. [SerializeField] SelectByMode _selectBy = SelectByMode.HighestDepthCamera;
  31. [SerializeField] ScanFrequencyMode _scanFrequency = ScanFrequencyMode.SceneLoad;
  32. [SerializeField] bool _scanHiddenCameras = false;
  33. [SerializeField] string _tag = "MainCamera";
  34. [SerializeField] string _name = "Main Camera";
  35. [SerializeField] Camera _camera = null;
  36. #if UNITY_EDITOR
  37. private const string SceneCameraName = "SceneCamera";
  38. #endif
  39. private Camera[] _cameraCache = new Camera[0];
  40. private int _cameraCount;
  41. private int _cameraCacheFrame = -1;
  42. private bool _selectionDirty = false;
  43. #if UNITY_EDITOR
  44. public int CameraCacheCount
  45. {
  46. get { return _cameraCount; }
  47. }
  48. public Camera[] CameraCache
  49. {
  50. get { return _cameraCache; }
  51. }
  52. #endif
  53. public Camera Camera
  54. {
  55. get { return _camera; }
  56. set { _camera = value; _selectBy = SelectByMode.Manual; }
  57. }
  58. public SelectByMode SelectBy
  59. {
  60. get { return _selectBy; }
  61. set { _selectBy = value; _selectionDirty = true; }
  62. }
  63. public ScanFrequencyMode ScanFrequency
  64. {
  65. get { return _scanFrequency; }
  66. set { _scanFrequency = value; ResetSceneLoading(); }
  67. }
  68. public bool ScanHiddenCameras
  69. {
  70. get { return _scanHiddenCameras; }
  71. set { _scanHiddenCameras = value; _selectionDirty = true; }
  72. }
  73. public string SelectTag
  74. {
  75. get { return _tag; }
  76. set { _tag = value; _selectionDirty = true; }
  77. }
  78. public string SelectName
  79. {
  80. get { return _name; }
  81. set { _name = value; _selectionDirty = true; }
  82. }
  83. void Awake()
  84. {
  85. ResetSceneLoading();
  86. }
  87. void Start()
  88. {
  89. ScanForCameraChange();
  90. }
  91. void OnValidate()
  92. {
  93. ResetSceneLoading();
  94. }
  95. void Update()
  96. {
  97. if (_selectionDirty || _scanFrequency == ScanFrequencyMode.Frame)
  98. {
  99. ScanForCameraChange();
  100. }
  101. }
  102. void OnDestroy()
  103. {
  104. SceneManager.sceneLoaded -= OnSceneLoaded;
  105. }
  106. void ResetSceneLoading()
  107. {
  108. SceneManager.sceneLoaded -= OnSceneLoaded;
  109. if (_scanFrequency == ScanFrequencyMode.SceneLoad)
  110. {
  111. SceneManager.sceneLoaded += OnSceneLoaded;
  112. }
  113. }
  114. void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  115. {
  116. if (_scanFrequency == ScanFrequencyMode.SceneLoad)
  117. {
  118. ScanForCameraChange();
  119. }
  120. }
  121. public bool ScanForCameraChange()
  122. {
  123. bool result = false;
  124. Camera camera = FindCamera();
  125. if (_camera != camera)
  126. {
  127. _camera = camera;
  128. if (_camera != null)
  129. {
  130. //Debug.Log("Camera " + _camera.name);
  131. }
  132. result = true;
  133. }
  134. _selectionDirty = false;
  135. return result;
  136. }
  137. Camera FindCamera()
  138. {
  139. Camera result = null;
  140. switch (_selectBy)
  141. {
  142. case SelectByMode.HighestDepthCamera:
  143. UpdateCameraCache();
  144. result = FindCameraByHighestDepth(_cameraCount, _cameraCache);
  145. break;
  146. case SelectByMode.MainCameraTag:
  147. result = Camera.main;
  148. break;
  149. case SelectByMode.EditorSceneView:
  150. #if UNITY_EDITOR
  151. UpdateCameraCache(true);
  152. result = FindCameraByName(_cameraCount, _cameraCache, SceneCameraName);
  153. #else
  154. Debug.LogWarning("[AVProMovieCapture] Scene View can only be captured in the Unity editor. Select a different camera.");
  155. #endif
  156. break;
  157. case SelectByMode.Tag:
  158. UpdateCameraCache();
  159. result = FindCameraByTag(_cameraCount, _cameraCache, _tag);
  160. break;
  161. case SelectByMode.Name:
  162. UpdateCameraCache();
  163. result = FindCameraByName(_cameraCount, _cameraCache, _name);
  164. break;
  165. case SelectByMode.Manual:
  166. result = _camera;
  167. break;
  168. }
  169. return result;
  170. }
  171. public void UpdateCameraCache(bool forceScanHiddenCameras = false)
  172. {
  173. // Prevent multiple scans per frame
  174. if (Time.frameCount == _cameraCacheFrame) return;
  175. if (!_scanHiddenCameras && !forceScanHiddenCameras)
  176. {
  177. // FAST - list active cameras
  178. if (_cameraCache.Length < Camera.allCamerasCount)
  179. {
  180. _cameraCache = new Camera[Camera.allCamerasCount];
  181. }
  182. _cameraCount = Camera.GetAllCameras(_cameraCache);
  183. }
  184. else
  185. {
  186. // SLOW - list all cameras
  187. _cameraCache = Resources.FindObjectsOfTypeAll<Camera>();
  188. _cameraCount = _cameraCache.Length;
  189. }
  190. _cameraCacheFrame = Time.frameCount;
  191. }
  192. static Camera FindCameraByHighestDepth(int cameraCount, Camera[] cameras)
  193. {
  194. Camera result = null;
  195. float maxDepth = float.MinValue;
  196. for (int i = 0; i < cameraCount; i++)
  197. {
  198. Camera c = cameras[i];
  199. if (result == null || c.depth > maxDepth)
  200. {
  201. result = c;
  202. maxDepth = c.depth;
  203. }
  204. }
  205. return result;
  206. }
  207. static Camera FindCameraByTag(int cameraCount, Camera[] cameras, string tag)
  208. {
  209. Camera result = null;
  210. for (int i = 0; i < cameraCount; i++)
  211. {
  212. Camera c = cameras[i];
  213. if (c.CompareTag(tag))
  214. {
  215. result = c;
  216. break;
  217. }
  218. }
  219. return result;
  220. }
  221. static Camera FindCameraByName(int cameraCount, Camera[] cameras, string name)
  222. {
  223. Camera result = null;
  224. for (int i = 0; i < cameraCount; i++)
  225. {
  226. Camera c = cameras[i];
  227. if (c.name == name)
  228. {
  229. result = c;
  230. break;
  231. }
  232. }
  233. return result;
  234. }
  235. }
  236. }