| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #if !UNITY_2019_1_OR_NEWER
- #define CINEMACHINE_TIMELINE
- #endif
- #if CINEMACHINE_TIMELINE
- using UnityEngine;
- using UnityEngine.Playables;
- using Cinemachine;
- using System.Collections.Generic;
- //namespace Cinemachine.Timeline
- //{
- internal sealed class CinemachineMixer : PlayableBehaviour
- {
- public delegate PlayableDirector MasterDirectorDelegate();
- static public MasterDirectorDelegate GetMasterPlayableDirector;
- // The brain that this track controls
- private CinemachineBrain mBrain;
- private int mBrainOverrideId = -1;
- private bool mPreviewPlay;
- #if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
- class ScrubbingCacheHelper
- {
- // Remember the active clips of the previous frame so we can track camera cuts
- public int ActivePlayableA;
- public int ActivePlayableB;
- struct ClipObjects
- {
- public List<List<CinemachineVirtualCameraBase>> Cameras;
- public float MaxDampTime;
- }
- List<ClipObjects> CachedObjects;
- static List<CinemachineVirtualCameraBase> scratch = new List<CinemachineVirtualCameraBase>();
- public void Init(Playable playable)
- {
- // Build our vcam registry for scrubbing updates
- CachedObjects = new List<ClipObjects>(playable.GetInputCount());
- for (int i = 0; i < playable.GetInputCount(); ++i)
- {
- var cs = new ClipObjects
- {
- Cameras = new List<List<CinemachineVirtualCameraBase>>(),
- };
- var clip = (ScriptPlayable<CinemachineShotPlayable>)playable.GetInput(i);
- CinemachineShotPlayable shot = clip.GetBehaviour();
- if (shot != null && shot.IsValid)
- {
- var mainVcam = shot.VirtualCamera;
- cs.Cameras.Add(new List<CinemachineVirtualCameraBase>());
- // Add all child cameras
- scratch.Clear();
- mainVcam.GetComponentsInChildren(scratch);
- for (int j = 0; j < scratch.Count; ++j)
- {
- var vcam = scratch[j];
- int nestLevel = 0;
- for (ICinemachineCamera p = vcam.ParentCamera;
- p != null && p != (ICinemachineCamera)mainVcam; p = p.ParentCamera)
- {
- ++nestLevel;
- }
- while (cs.Cameras.Count <= nestLevel)
- cs.Cameras.Add(new List<CinemachineVirtualCameraBase>());
- cs.Cameras[nestLevel].Add(vcam);
- cs.MaxDampTime = Mathf.Max(cs.MaxDampTime, vcam.GetMaxDampTime());
- }
- }
- CachedObjects.Add(cs);
- }
- }
- public void ScrubToHere(float currentTime, int playableIndex, bool isCut, float timeInClip, Vector3 up)
- {
- TargetPositionCache.CurrentTime = currentTime;
- if (TargetPositionCache.CacheMode == TargetPositionCache.Mode.Record)
- {
- // If the clip is newly activated, force the time to clip start,
- // in case timeline skipped some frames. This will avoid target lerps between shots.
- if (Time.frameCount != TargetPositionCache.CurrentFrame)
- TargetPositionCache.IsCameraCut = false;
- TargetPositionCache.CurrentFrame = Time.frameCount;
- if (isCut)
- TargetPositionCache.IsCameraCut = true;
- return;
- }
- if (!TargetPositionCache.HasHurrentTime)
- return;
- var cs = CachedObjects[playableIndex];
- float stepSize = TargetPositionCache.CacheStepSize;
- // Impose upper limit on damping time, to avoid simulating too many frames
- float maxDampTime = Mathf.Max(0, timeInClip - stepSize);
- maxDampTime = Mathf.Min(cs.MaxDampTime, Mathf.Min(maxDampTime, 4.0f));
- var endTime = TargetPositionCache.CurrentTime;
- var startTime = Mathf.Max(
- TargetPositionCache.CacheTimeRange.Start + stepSize, endTime - maxDampTime);
- var numSteps = Mathf.FloorToInt((endTime - startTime) / stepSize);
- for (int step = numSteps; step >= 0; --step)
- {
- var t = Mathf.Max(startTime, endTime - step * stepSize);
- TargetPositionCache.CurrentTime = t;
- var deltaTime = (step == numSteps) ? -1
- : (t - startTime < stepSize ? t - startTime : stepSize);
- // Update all relevant vcams, leaf-most first
- for (int i = cs.Cameras.Count - 1; i >= 0; --i)
- {
- var sublist = cs.Cameras[i];
- for (int j = sublist.Count - 1; j >= 0; --j)
- {
- var vcam = sublist[j];
- if (deltaTime < 0)
- vcam.ForceCameraPosition(
- TargetPositionCache.GetTargetPosition(vcam.transform),
- TargetPositionCache.GetTargetRotation(vcam.transform));
- vcam.InternalUpdateCameraState(up, deltaTime);
- }
- }
- }
- }
- }
- ScrubbingCacheHelper m_ScrubbingCacheHelper;
- #endif
- #if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
- public override void OnGraphStart(Playable playable)
- {
- base.OnGraphStart(playable);
- m_ScrubbingCacheHelper = null;
- }
- #endif
-
- public override void OnPlayableDestroy(Playable playable)
- {
- if (mBrain != null)
- mBrain.ReleaseCameraOverride(mBrainOverrideId); // clean up
- mBrainOverrideId = -1;
- #if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
- m_ScrubbingCacheHelper = null;
- #endif
- }
- public override void PrepareFrame(Playable playable, FrameData info)
- {
- mPreviewPlay = false;
- #if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
- var cacheMode = TargetPositionCache.Mode.Disabled;
- if (!Application.isPlaying)
- {
- if (GetMasterPlayableDirector != null)
- {
- var d = GetMasterPlayableDirector();
- if (d != null && d.playableGraph.IsValid())
- mPreviewPlay = GetMasterPlayableDirector().playableGraph.IsPlaying();
- }
- if (TargetPositionCache.UseCache)
- {
- cacheMode = mPreviewPlay ? TargetPositionCache.Mode.Record : TargetPositionCache.Mode.Playback;
- if (m_ScrubbingCacheHelper == null)
- {
- m_ScrubbingCacheHelper = new ScrubbingCacheHelper();
- m_ScrubbingCacheHelper.Init(playable);
- }
- }
- }
- TargetPositionCache.CacheMode = cacheMode;
- #endif
- }
- public override void ProcessFrame(Playable playable, FrameData info, object playerData)
- {
- base.ProcessFrame(playable, info, playerData);
- // Get the brain that this track controls.
- // Older versions of timeline sent the gameObject by mistake.
- GameObject go = playerData as GameObject;
- if (go == null)
- mBrain = (CinemachineBrain)playerData;
- else
- mBrain = go.GetComponent<CinemachineBrain>();
- if (mBrain == null)
- return;
- // Find which clips are active. We can process a maximum of 2.
- // In the case that the weights don't add up to 1, the outgoing weight
- // will be calculated as the inverse of the incoming weight.
- int activeInputs = 0;
- int clipIndexA = -1;
- int clipIndexB = -1;
- bool incomingIsA = false; // Assume that incoming clip is clip B
- float weightB = 1;
- for (int i = 0; i < playable.GetInputCount(); ++i)
- {
- float weight = playable.GetInputWeight(i);
- var clip = (ScriptPlayable<CinemachineShotPlayable>)playable.GetInput(i);
- CinemachineShotPlayable shot = clip.GetBehaviour();
- if (shot != null && shot.IsValid
- && playable.GetPlayState() == PlayState.Playing
- && weight > 0)
- {
- clipIndexA = clipIndexB;
- clipIndexB = i;
- weightB = weight;
- if (++activeInputs == 2)
- {
- // Deduce which clip is incoming (timeline doesn't know)
- var clipA = playable.GetInput(clipIndexA);
- // Incoming has later start time (therefore earlier current time)
- incomingIsA = clip.GetTime() >= clipA.GetTime();
- // If same start time, longer clip is incoming
- if (clip.GetTime() == clipA.GetTime())
- incomingIsA = clip.GetDuration() < clipA.GetDuration();
- break;
- }
- }
- }
- // Special case: check for only one clip that's fading out - it must be outgoing
- if (activeInputs == 1 && weightB < 1
- && playable.GetInput(clipIndexB).GetTime() > playable.GetInput(clipIndexB).GetDuration() / 2)
- {
- incomingIsA = true;
- }
- if (incomingIsA)
- {
- (clipIndexA, clipIndexB) = (clipIndexB, clipIndexA);
- weightB = 1 - weightB;
- }
- ICinemachineCamera camA = null;
- if (clipIndexA >= 0)
- {
- CinemachineShotPlayable shot
- = ((ScriptPlayable<CinemachineShotPlayable>)playable.GetInput(clipIndexA)).GetBehaviour();
- camA = shot.VirtualCamera;
- }
- ICinemachineCamera camB = null;
- if (clipIndexB >= 0)
- {
- CinemachineShotPlayable shot
- = ((ScriptPlayable<CinemachineShotPlayable>)playable.GetInput(clipIndexB)).GetBehaviour();
- camB = shot.VirtualCamera;
- }
- // Override the Cinemachine brain with our results
- mBrainOverrideId = mBrain.SetCameraOverride(
- mBrainOverrideId, camA, camB, weightB, GetDeltaTime(info.deltaTime));
- #if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
- if (m_ScrubbingCacheHelper != null && TargetPositionCache.CacheMode != TargetPositionCache.Mode.Disabled)
- {
- bool isNewB = (m_ScrubbingCacheHelper.ActivePlayableA != clipIndexB
- && m_ScrubbingCacheHelper.ActivePlayableB != clipIndexB);
- m_ScrubbingCacheHelper.ActivePlayableA = clipIndexA;
- m_ScrubbingCacheHelper.ActivePlayableB = clipIndexB;
- if (clipIndexA >= 0)
- m_ScrubbingCacheHelper.ScrubToHere(
- (float)GetMasterPlayableDirector().time, clipIndexA, false,
- (float)playable.GetInput(clipIndexA).GetTime(), mBrain.DefaultWorldUp);
- if (clipIndexB >= 0)
- m_ScrubbingCacheHelper.ScrubToHere(
- (float)GetMasterPlayableDirector().time, clipIndexB, isNewB && weightB > 0.99f,
- (float)playable.GetInput(clipIndexB).GetTime(), mBrain.DefaultWorldUp);
- }
- #endif
- }
- float GetDeltaTime(float deltaTime)
- {
- if (mPreviewPlay || Application.isPlaying)
- return deltaTime;
- // We're scrubbing or paused
- if (TargetPositionCache.CacheMode == TargetPositionCache.Mode.Playback
- && TargetPositionCache.HasHurrentTime)
- {
- return 0;
- }
- return -1;
- }
- }
- //}
- #endif
|