using UnityEngine; using UnityEngine.SceneManagement; //----------------------------------------------------------------------------- // Copyright 2012-2022 RenderHeads Ltd. All rights reserved. //----------------------------------------------------------------------------- namespace RenderHeads.Media.AVProMovieCapture { /// /// Selects the camera to use for captures based on various factors /// TODO: add support for persisting across scene changes /// [AddComponentMenu("AVPro Movie Capture/Utils/Camera Selector", 300)] public class CameraSelector : MonoBehaviour { public enum SelectByMode { HighestDepthCamera, MainCameraTag, EditorSceneView, Tag, Name, Manual, } public enum ScanFrequencyMode { Manual, SceneLoad, Frame, } [SerializeField] SelectByMode _selectBy = SelectByMode.HighestDepthCamera; [SerializeField] ScanFrequencyMode _scanFrequency = ScanFrequencyMode.SceneLoad; [SerializeField] bool _scanHiddenCameras = false; [SerializeField] string _tag = "MainCamera"; [SerializeField] string _name = "Main Camera"; [SerializeField] Camera _camera = null; #if UNITY_EDITOR private const string SceneCameraName = "SceneCamera"; #endif private Camera[] _cameraCache = new Camera[0]; private int _cameraCount; private int _cameraCacheFrame = -1; private bool _selectionDirty = false; #if UNITY_EDITOR public int CameraCacheCount { get { return _cameraCount; } } public Camera[] CameraCache { get { return _cameraCache; } } #endif public Camera Camera { get { return _camera; } set { _camera = value; _selectBy = SelectByMode.Manual; } } public SelectByMode SelectBy { get { return _selectBy; } set { _selectBy = value; _selectionDirty = true; } } public ScanFrequencyMode ScanFrequency { get { return _scanFrequency; } set { _scanFrequency = value; ResetSceneLoading(); } } public bool ScanHiddenCameras { get { return _scanHiddenCameras; } set { _scanHiddenCameras = value; _selectionDirty = true; } } public string SelectTag { get { return _tag; } set { _tag = value; _selectionDirty = true; } } public string SelectName { get { return _name; } set { _name = value; _selectionDirty = true; } } void Awake() { ResetSceneLoading(); } void Start() { ScanForCameraChange(); } void OnValidate() { ResetSceneLoading(); } void Update() { if (_selectionDirty || _scanFrequency == ScanFrequencyMode.Frame) { ScanForCameraChange(); } } void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } void ResetSceneLoading() { SceneManager.sceneLoaded -= OnSceneLoaded; if (_scanFrequency == ScanFrequencyMode.SceneLoad) { SceneManager.sceneLoaded += OnSceneLoaded; } } void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (_scanFrequency == ScanFrequencyMode.SceneLoad) { ScanForCameraChange(); } } public bool ScanForCameraChange() { bool result = false; Camera camera = FindCamera(); if (_camera != camera) { _camera = camera; if (_camera != null) { //Debug.Log("Camera " + _camera.name); } result = true; } _selectionDirty = false; return result; } Camera FindCamera() { Camera result = null; switch (_selectBy) { case SelectByMode.HighestDepthCamera: UpdateCameraCache(); result = FindCameraByHighestDepth(_cameraCount, _cameraCache); break; case SelectByMode.MainCameraTag: result = Camera.main; break; case SelectByMode.EditorSceneView: #if UNITY_EDITOR UpdateCameraCache(true); result = FindCameraByName(_cameraCount, _cameraCache, SceneCameraName); #else Debug.LogWarning("[AVProMovieCapture] Scene View can only be captured in the Unity editor. Select a different camera."); #endif break; case SelectByMode.Tag: UpdateCameraCache(); result = FindCameraByTag(_cameraCount, _cameraCache, _tag); break; case SelectByMode.Name: UpdateCameraCache(); result = FindCameraByName(_cameraCount, _cameraCache, _name); break; case SelectByMode.Manual: result = _camera; break; } return result; } public void UpdateCameraCache(bool forceScanHiddenCameras = false) { // Prevent multiple scans per frame if (Time.frameCount == _cameraCacheFrame) return; if (!_scanHiddenCameras && !forceScanHiddenCameras) { // FAST - list active cameras if (_cameraCache.Length < Camera.allCamerasCount) { _cameraCache = new Camera[Camera.allCamerasCount]; } _cameraCount = Camera.GetAllCameras(_cameraCache); } else { // SLOW - list all cameras _cameraCache = Resources.FindObjectsOfTypeAll(); _cameraCount = _cameraCache.Length; } _cameraCacheFrame = Time.frameCount; } static Camera FindCameraByHighestDepth(int cameraCount, Camera[] cameras) { Camera result = null; float maxDepth = float.MinValue; for (int i = 0; i < cameraCount; i++) { Camera c = cameras[i]; if (result == null || c.depth > maxDepth) { result = c; maxDepth = c.depth; } } return result; } static Camera FindCameraByTag(int cameraCount, Camera[] cameras, string tag) { Camera result = null; for (int i = 0; i < cameraCount; i++) { Camera c = cameras[i]; if (c.CompareTag(tag)) { result = c; break; } } return result; } static Camera FindCameraByName(int cameraCount, Camera[] cameras, string name) { Camera result = null; for (int i = 0; i < cameraCount; i++) { Camera c = cameras[i]; if (c.name == name) { result = c; break; } } return result; } } }