123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- #if UNITY_2017_1_OR_NEWER
- using UnityEngine;
- using System.Collections.Generic;
- using UnityEngine.SceneManagement;
- using UnityEngine.Playables;
- //-----------------------------------------------------------------------------
- // Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace RenderHeads.Media.AVProMovieCapture
- {
- /// <summary>
- /// Controls timeline updates time during offline captures
- /// This class used to try to control the timestep of the Timeline, but features like Markers/Signals no longer work in Manual update mode
- /// So now we just change any DSPClock directors to GameTime
- /// </summary>
- [AddComponentMenu("AVPro Movie Capture/Utils/Timeline Controller", 300)]
- public class TimelineController : MonoBehaviour
- {
- public enum ScanFrequencyMode
- {
- SceneLoad,
- Frame,
- }
- [SerializeField] ScanFrequencyMode _scanFrequency = ScanFrequencyMode.SceneLoad;
- public ScanFrequencyMode ScanFrequency
- {
- get { return _scanFrequency; }
- set { _scanFrequency = value; ResetSceneLoading(); }
- }
- internal class TimelineInstance
- {
- private PlayableDirector _director = null;
- private DirectorUpdateMode _originalTimeUpdateMode = DirectorUpdateMode.DSPClock;
- private bool _isControlling = false;
- private bool _isCapturing = false;
- internal TimelineInstance(PlayableDirector director)
- {
- _director = director;
- }
- internal bool Is(PlayableDirector director)
- {
- return (_director == director);
- }
- internal void StartCapture()
- {
- // First capture to touch the playable directors
- if (!_isCapturing)
- {
- // Null check in case director no longer exists
- if (_director != null)
- {
- // Want to manually update?
- // TODO: should we include ALL directors, as they may switch from manual to something else later on?
- // DSPClock doesn't change rate when rendering offline, so we need to change to GameTime
- _isControlling = (_director.timeUpdateMode == DirectorUpdateMode.DSPClock);
- if (_isControlling)
- {
- // Cache original update mode
- _originalTimeUpdateMode = _director.timeUpdateMode;
- bool wasPlaying = (_director.state == PlayState.Playing);
- // Set to manual update mode
- // NOTE: Prior to Unity 2018.2 changing from DSP Clock to Manual did nothing, as DSP Clock mode was set to ignore manual updates
- _director.timeUpdateMode = DirectorUpdateMode.GameTime;
-
- // NOTE: In newer versions of Unity (post 2018.2) changing the timeUpdateMode to Manual pauses playback, so we must resume it
- if (wasPlaying && _director.state == PlayState.Paused)
- {
- _director.Resume();
- }
- }
- }
- _isCapturing = true;
- }
- }
- #if false
- internal void Update(float deltaTime)
- {
- if (_isControlling && _isCapturing)
- {
- if (_director != null && _director.isActiveAndEnabled)
- {
- if (_director.state == PlayState.Playing)
- {
- double time = _director.time + deltaTime;
- if (time < _director.duration)
- {
- _director.time = time;
- _director.Evaluate();
- }
- else
- {
- switch (_director.extrapolationMode)
- {
- case DirectorWrapMode.Loop:
- _director.time = time % _director.duration;
- _director.Evaluate();
- break;
- case DirectorWrapMode.Hold:
- _director.time = _director.duration;
- _director.Evaluate();
- break;
- case DirectorWrapMode.None:
- _director.time = 0f;
- _director.Pause();
- break;
- }
- }
- }
- }
- }
- }
- #endif
- internal void StopCapture()
- {
- if (_isCapturing)
- {
- // TODO: what happens to the director when the scene is unloaded?
- if (_director != null)
- {
- // We were controlling?
- if (_isControlling)
- {
- bool wasPlaying = (_director.state == PlayState.Playing);
- // Revert update mode to original
- _director.timeUpdateMode = _originalTimeUpdateMode;
- if (wasPlaying)
- {
- // Timeline seems to get paused after changing play mode (in some versions of Unity), only a pause and resume keeps it going
- _director.Pause();
- _director.Resume();
- }
- _isControlling = false;
- }
- }
- _isCapturing = false;
- }
- }
- }
- private List<TimelineInstance> _timelines = new List<TimelineInstance>(8);
- void Awake()
- {
- ResetSceneLoading();
- }
- void OnValidate()
- {
- ResetSceneLoading();
- }
- internal void UpdateFrame()
- {
- if (_scanFrequency == ScanFrequencyMode.Frame)
- {
- ScanForPlayableDirectors();
- }
- #if false
- foreach (TimelineInstance timeline in _timelines)
- {
- timeline.Update(Time.deltaTime);
- }
- #endif
- }
- internal void StartCapture()
- {
- ScanForPlayableDirectors();
- foreach (TimelineInstance timeline in _timelines)
- {
- timeline.StartCapture();
- }
- }
- internal void StopCapture()
- {
- foreach (TimelineInstance timeline in _timelines)
- {
- timeline.StopCapture();
- }
- }
- public void ScanForPlayableDirectors()
- {
- // Remove any timeline instances with deleted (null) directors
- for (int i = 0; i < _timelines.Count; i++)
- {
- TimelineInstance timeline = _timelines[i];
- if (timeline.Is(null))
- {
- _timelines.RemoveAt(i); i--;
- }
- }
- // Find all inactive and active directors
- PlayableDirector[] directors = Resources.FindObjectsOfTypeAll<PlayableDirector>();
- // Create a unique instance for each director
- foreach (PlayableDirector playableDirector in directors)
- {
- // Check we don't already have this director
- bool hasDirector = false;
- foreach (TimelineInstance timeline in _timelines)
- {
- if (timeline.Is(playableDirector))
- {
- hasDirector = true;
- break;
- }
- }
- // Add to the list
- if (!hasDirector)
- {
- _timelines.Add(new TimelineInstance(playableDirector));
- }
- }
- }
- void OnDestroy()
- {
- SceneManager.sceneLoaded -= OnSceneLoaded;
- StopCapture();
- }
- void ResetSceneLoading()
- {
- SceneManager.sceneLoaded -= OnSceneLoaded;
- if (_scanFrequency == ScanFrequencyMode.SceneLoad)
- {
- SceneManager.sceneLoaded += OnSceneLoaded;
- }
- }
-
- void OnSceneLoaded(Scene scene, LoadSceneMode mode)
- {
- if (_scanFrequency == ScanFrequencyMode.SceneLoad)
- {
- ScanForPlayableDirectors();
- }
- }
- }
- }
- #endif
|