CinemachineBrain.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. using Cinemachine.Utility;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. using UnityEngine.SceneManagement;
  8. using UnityEngine.Serialization;
  9. #if CINEMACHINE_HDRP || CINEMACHINE_LWRP_7_0_0
  10. #if CINEMACHINE_HDRP_7_0_0
  11. using UnityEngine.Rendering.HighDefinition;
  12. #else
  13. #if CINEMACHINE_LWRP_7_0_0
  14. using UnityEngine.Rendering.Universal;
  15. #else
  16. using UnityEngine.Experimental.Rendering.HDPipeline;
  17. #endif
  18. #endif
  19. #endif
  20. namespace Cinemachine
  21. {
  22. /// <summary>
  23. /// CinemachineBrain is the link between the Unity Camera and the Cinemachine Virtual
  24. /// Cameras in the scene. It monitors the priority stack to choose the current
  25. /// Virtual Camera, and blend with another if necessary. Finally and most importantly,
  26. /// it applies the Virtual Camera state to the attached Unity Camera.
  27. ///
  28. /// The CinemachineBrain is also the place where rules for blending between virtual cameras
  29. /// are defined. Camera blending is an interpolation over time of one virtual camera
  30. /// position and state to another. If you think of virtual cameras as cameramen, then
  31. /// blending is a little like one cameraman smoothly passing the camera to another cameraman.
  32. /// You can specify the time over which to blend, as well as the blend curve shape.
  33. /// Note that a camera cut is just a zero-time blend.
  34. /// </summary>
  35. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  36. // [RequireComponent(typeof(Camera))] // strange but true: we can live without it
  37. [DisallowMultipleComponent]
  38. #if UNITY_2018_3_OR_NEWER
  39. [ExecuteAlways]
  40. #else
  41. [ExecuteInEditMode]
  42. #endif
  43. [AddComponentMenu("Cinemachine/CinemachineBrain")]
  44. [SaveDuringPlay]
  45. [HelpURL(Documentation.BaseURL + "manual/CinemachineBrainProperties.html")]
  46. public class CinemachineBrain : MonoBehaviour
  47. {
  48. /// <summary>
  49. /// When enabled, the current camera and blend will be indicated in the
  50. /// game window, for debugging.
  51. /// </summary>
  52. [Tooltip("When enabled, the current camera and blend will be indicated in "
  53. + "the game window, for debugging")]
  54. public bool m_ShowDebugText = false;
  55. /// <summary>
  56. /// When enabled, shows the camera's frustum in the scene view.
  57. /// </summary>
  58. [Tooltip("When enabled, the camera's frustum will be shown at all times "
  59. + "in the scene view")]
  60. public bool m_ShowCameraFrustum = true;
  61. /// <summary>
  62. /// When enabled, the cameras will always respond in real-time to user input and damping,
  63. /// even if the game is running in slow motion
  64. /// </summary>
  65. [Tooltip("When enabled, the cameras will always respond in real-time to user input "
  66. + "and damping, even if the game is running in slow motion")]
  67. public bool m_IgnoreTimeScale = false;
  68. /// <summary>
  69. /// If set, this object's Y axis will define the worldspace Up vector for all the
  70. /// virtual cameras. This is useful in top-down game environments. If not set, Up is worldspace Y.
  71. /// </summary>
  72. [Tooltip("If set, this object's Y axis will define the worldspace Up vector for all the "
  73. + "virtual cameras. This is useful for instance in top-down game environments. "
  74. + "If not set, Up is worldspace Y. Setting this appropriately is important, "
  75. + "because Virtual Cameras don't like looking straight up or straight down.")]
  76. public Transform m_WorldUpOverride;
  77. /// <summary>This enum defines the options available for the update method.</summary>
  78. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  79. public enum UpdateMethod
  80. {
  81. /// <summary>Virtual cameras are updated in sync with the Physics module, in FixedUpdate</summary>
  82. FixedUpdate,
  83. /// <summary>Virtual cameras are updated in MonoBehaviour LateUpdate.</summary>
  84. LateUpdate,
  85. /// <summary>Virtual cameras are updated according to how the target is updated.</summary>
  86. SmartUpdate,
  87. /// <summary>Virtual cameras are not automatically updated, client must explicitly call
  88. /// the CinemachineBrain's ManualUpdate() method.</summary>
  89. ManualUpdate
  90. };
  91. /// <summary>Depending on how the target objects are animated, adjust the update method to
  92. /// minimize the potential jitter. Use FixedUpdate if all your targets are animated with for RigidBody animation.
  93. /// SmartUpdate will choose the best method for each virtual camera, depending
  94. /// on how the target is animated.</summary>
  95. [Tooltip("The update time for the vcams. Use FixedUpdate if all your targets are animated "
  96. + "during FixedUpdate (e.g. RigidBodies), LateUpdate if all your targets are animated "
  97. + "during the normal Update loop, and SmartUpdate if you want Cinemachine to do the "
  98. + "appropriate thing on a per-target basis. SmartUpdate is the recommended setting")]
  99. public UpdateMethod m_UpdateMethod = UpdateMethod.SmartUpdate;
  100. /// <summary>This enum defines the options available for the update method.</summary>
  101. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  102. public enum BrainUpdateMethod
  103. {
  104. /// <summary>Camera is updated in sync with the Physics module, in FixedUpdate</summary>
  105. FixedUpdate,
  106. /// <summary>Camera is updated in MonoBehaviour LateUpdate (or when ManualUpdate is called).</summary>
  107. LateUpdate
  108. };
  109. /// <summary>The update time for the Brain, i.e. when the blends are evaluated and the
  110. /// brain's transform is updated.</summary>
  111. [Tooltip("The update time for the Brain, i.e. when the blends are evaluated and "
  112. + "the brain's transform is updated")]
  113. public BrainUpdateMethod m_BlendUpdateMethod = BrainUpdateMethod.LateUpdate;
  114. /// <summary>
  115. /// The blend which is used if you don't explicitly define a blend between two Virtual Cameras.
  116. /// </summary>
  117. [CinemachineBlendDefinitionProperty]
  118. [Tooltip("The blend that is used in cases where you haven't explicitly defined a "
  119. + "blend between two Virtual Cameras")]
  120. public CinemachineBlendDefinition m_DefaultBlend
  121. = new CinemachineBlendDefinition(CinemachineBlendDefinition.Style.EaseInOut, 2f);
  122. /// <summary>
  123. /// This is the asset which contains custom settings for specific blends.
  124. /// </summary>
  125. [Tooltip("This is the asset that contains custom settings for blends between "
  126. + "specific virtual cameras in your scene")]
  127. public CinemachineBlenderSettings m_CustomBlends = null;
  128. /// <summary>
  129. /// Get the Unity Camera that is attached to this GameObject. This is the camera
  130. /// that will be controlled by the brain.
  131. /// </summary>
  132. public Camera OutputCamera
  133. {
  134. get
  135. {
  136. if (m_OutputCamera == null && !Application.isPlaying)
  137. #if UNITY_2019_2_OR_NEWER
  138. TryGetComponent(out m_OutputCamera);
  139. #else
  140. m_OutputCamera = GetComponent<Camera>();
  141. #endif
  142. return m_OutputCamera;
  143. }
  144. }
  145. private Camera m_OutputCamera = null; // never use directly - use accessor
  146. /// <summary>Event with a CinemachineBrain parameter</summary>
  147. [Serializable] public class BrainEvent : UnityEvent<CinemachineBrain> {}
  148. /// <summary>
  149. /// Event that is fired when a virtual camera is activated.
  150. /// The parameters are (incoming_vcam, outgoing_vcam), in that order.
  151. /// </summary>
  152. [Serializable] public class VcamActivatedEvent : UnityEvent<ICinemachineCamera, ICinemachineCamera> {}
  153. /// <summary>This event will fire whenever a virtual camera goes live and there is no blend</summary>
  154. [Tooltip("This event will fire whenever a virtual camera goes live and there is no blend")]
  155. public BrainEvent m_CameraCutEvent = new BrainEvent();
  156. /// <summary>This event will fire whenever a virtual camera goes live. If a blend is involved,
  157. /// then the event will fire on the first frame of the blend.
  158. ///
  159. /// The Parameters are (incoming_vcam, outgoing_vcam), in that order.</summary>
  160. [Tooltip("This event will fire whenever a virtual camera goes live. If a blend is "
  161. + "involved, then the event will fire on the first frame of the blend.")]
  162. public VcamActivatedEvent m_CameraActivatedEvent = new VcamActivatedEvent();
  163. /// <summary>
  164. /// API for the Unity Editor.
  165. /// Show this camera no matter what. This is static, and so affects all Cinemachine brains.
  166. /// </summary>
  167. public static ICinemachineCamera SoloCamera
  168. {
  169. get { return mSoloCamera; }
  170. set
  171. {
  172. if (value != null && !CinemachineCore.Instance.IsLive(value))
  173. value.OnTransitionFromCamera(null, Vector3.up, CinemachineCore.DeltaTime);
  174. mSoloCamera = value;
  175. }
  176. }
  177. /// <summary>API for the Unity Editor.</summary>
  178. /// <returns>Color used to indicate that a camera is in Solo mode.</returns>
  179. public static Color GetSoloGUIColor() { return Color.Lerp(Color.red, Color.yellow, 0.8f); }
  180. /// <summary>Get the default world up for the virtual cameras.</summary>
  181. public Vector3 DefaultWorldUp
  182. { get { return (m_WorldUpOverride != null) ? m_WorldUpOverride.transform.up : Vector3.up; } }
  183. private static ICinemachineCamera mSoloCamera;
  184. private Coroutine mPhysicsCoroutine;
  185. private int m_LastFrameUpdated;
  186. private void OnEnable()
  187. {
  188. // Make sure there is a first stack frame
  189. if (mFrameStack.Count == 0)
  190. mFrameStack.Add(new BrainFrame());
  191. m_OutputCamera = GetComponent<Camera>();
  192. CinemachineCore.Instance.AddActiveBrain(this);
  193. CinemachineDebug.OnGUIHandlers -= OnGuiHandler;
  194. CinemachineDebug.OnGUIHandlers += OnGuiHandler;
  195. // We check in after the physics system has had a chance to move things
  196. mPhysicsCoroutine = StartCoroutine(AfterPhysics());
  197. SceneManager.sceneLoaded += OnSceneLoaded;
  198. SceneManager.sceneUnloaded += OnSceneUnloaded;
  199. }
  200. private void OnDisable()
  201. {
  202. SceneManager.sceneLoaded -= OnSceneLoaded;
  203. SceneManager.sceneUnloaded -= OnSceneUnloaded;
  204. CinemachineDebug.OnGUIHandlers -= OnGuiHandler;
  205. CinemachineCore.Instance.RemoveActiveBrain(this);
  206. mFrameStack.Clear();
  207. StopCoroutine(mPhysicsCoroutine);
  208. }
  209. void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  210. {
  211. if (Time.frameCount == m_LastFrameUpdated && mFrameStack.Count > 0)
  212. ManualUpdate();
  213. }
  214. void OnSceneUnloaded(Scene scene)
  215. {
  216. if (Time.frameCount == m_LastFrameUpdated && mFrameStack.Count > 0)
  217. ManualUpdate();
  218. }
  219. private void Start()
  220. {
  221. m_LastFrameUpdated = -1;
  222. UpdateVirtualCameras(CinemachineCore.UpdateFilter.Late, -1f);
  223. }
  224. private void OnGuiHandler()
  225. {
  226. if (!m_ShowDebugText)
  227. CinemachineDebug.ReleaseScreenPos(this);
  228. else
  229. {
  230. // Show the active camera and blend
  231. var sb = CinemachineDebug.SBFromPool();
  232. Color color = GUI.color;
  233. sb.Length = 0;
  234. sb.Append("CM ");
  235. sb.Append(gameObject.name);
  236. sb.Append(": ");
  237. if (SoloCamera != null)
  238. {
  239. sb.Append("SOLO ");
  240. GUI.color = GetSoloGUIColor();
  241. }
  242. if (IsBlending)
  243. sb.Append(ActiveBlend.Description);
  244. else
  245. {
  246. ICinemachineCamera vcam = ActiveVirtualCamera;
  247. if (vcam == null)
  248. sb.Append("(none)");
  249. else
  250. {
  251. sb.Append("[");
  252. sb.Append(vcam.Name);
  253. sb.Append("]");
  254. }
  255. }
  256. string text = sb.ToString();
  257. Rect r = CinemachineDebug.GetScreenPos(this, text, GUI.skin.box);
  258. GUI.Label(r, text, GUI.skin.box);
  259. GUI.color = color;
  260. CinemachineDebug.ReturnToPool(sb);
  261. }
  262. }
  263. #if UNITY_EDITOR
  264. private void OnGUI()
  265. {
  266. if (CinemachineDebug.OnGUIHandlers != null)
  267. CinemachineDebug.OnGUIHandlers();
  268. }
  269. #endif
  270. WaitForFixedUpdate mWaitForFixedUpdate = new WaitForFixedUpdate();
  271. private IEnumerator AfterPhysics()
  272. {
  273. while (true)
  274. {
  275. // FixedUpdate can be called multiple times per frame
  276. yield return mWaitForFixedUpdate;
  277. if (m_UpdateMethod == UpdateMethod.FixedUpdate
  278. || m_UpdateMethod == UpdateMethod.SmartUpdate)
  279. {
  280. CinemachineCore.UpdateFilter filter = CinemachineCore.UpdateFilter.Fixed;
  281. if (m_UpdateMethod == UpdateMethod.SmartUpdate)
  282. {
  283. // Track the targets
  284. UpdateTracker.OnUpdate(UpdateTracker.UpdateClock.Fixed);
  285. filter = CinemachineCore.UpdateFilter.SmartFixed;
  286. }
  287. UpdateVirtualCameras(filter, GetEffectiveDeltaTime(true));
  288. }
  289. // Choose the active vcam and apply it to the Unity camera
  290. if (m_BlendUpdateMethod == BrainUpdateMethod.FixedUpdate)
  291. {
  292. UpdateFrame0(Time.fixedDeltaTime);
  293. ProcessActiveCamera(Time.fixedDeltaTime);
  294. }
  295. }
  296. }
  297. private void LateUpdate()
  298. {
  299. if (m_UpdateMethod != UpdateMethod.ManualUpdate)
  300. ManualUpdate();
  301. }
  302. /// <summary>
  303. /// Call this method explicitly from an external script to update the virtual cameras
  304. /// and position the main camera, if the UpdateMode is set to ManualUpdate.
  305. /// For other update modes, this method is called automatically, and should not be
  306. /// called from elsewhere.
  307. /// </summary>
  308. public void ManualUpdate()
  309. {
  310. m_LastFrameUpdated = Time.frameCount;
  311. float deltaTime = GetEffectiveDeltaTime(false);
  312. if (!Application.isPlaying || m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
  313. UpdateFrame0(deltaTime);
  314. ComputeCurrentBlend(ref mCurrentLiveCameras, 0);
  315. if (m_UpdateMethod == UpdateMethod.FixedUpdate)
  316. {
  317. // Special handling for fixed update: cameras that have been enabled
  318. // since the last physics frame must be updated now
  319. if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
  320. {
  321. CinemachineCore.Instance.CurrentUpdateFilter = CinemachineCore.UpdateFilter.Fixed;
  322. if (SoloCamera == null)
  323. mCurrentLiveCameras.UpdateCameraState(
  324. DefaultWorldUp, GetEffectiveDeltaTime(true));
  325. }
  326. }
  327. else
  328. {
  329. CinemachineCore.UpdateFilter filter = CinemachineCore.UpdateFilter.Late;
  330. if (m_UpdateMethod == UpdateMethod.SmartUpdate)
  331. {
  332. // Track the targets
  333. UpdateTracker.OnUpdate(UpdateTracker.UpdateClock.Late);
  334. filter = CinemachineCore.UpdateFilter.SmartLate;
  335. }
  336. UpdateVirtualCameras(filter, deltaTime);
  337. }
  338. // Choose the active vcam and apply it to the Unity camera
  339. if (!Application.isPlaying || m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
  340. ProcessActiveCamera(deltaTime);
  341. }
  342. #if UNITY_EDITOR
  343. /// This is only needed in editor mode to force timeline to call OnGUI while
  344. /// timeline is up and the game is not running, in order to allow dragging
  345. /// the composer guide in the game view.
  346. private void OnPreCull()
  347. {
  348. if (!Application.isPlaying)
  349. {
  350. // Note: this call will cause any screen canvas attached to the camera
  351. // to be painted one frame out of sync. It will only happen in the editor when not playing.
  352. ProcessActiveCamera(GetEffectiveDeltaTime(false));
  353. }
  354. }
  355. #endif
  356. private float GetEffectiveDeltaTime(bool fixedDelta)
  357. {
  358. if (CinemachineCore.UniformDeltaTimeOverride >= 0)
  359. return CinemachineCore.UniformDeltaTimeOverride;
  360. if (SoloCamera != null)
  361. return Time.unscaledDeltaTime;
  362. if (!Application.isPlaying)
  363. {
  364. for (int i = mFrameStack.Count - 1; i > 0; --i)
  365. {
  366. var frame = mFrameStack[i];
  367. if (frame.Active)
  368. return frame.deltaTimeOverride;
  369. }
  370. return -1;
  371. }
  372. if (m_IgnoreTimeScale)
  373. return fixedDelta ? Time.fixedDeltaTime : Time.unscaledDeltaTime;
  374. return fixedDelta ? Time.fixedDeltaTime : Time.deltaTime;
  375. }
  376. private void UpdateVirtualCameras(CinemachineCore.UpdateFilter updateFilter, float deltaTime)
  377. {
  378. // We always update all active virtual cameras
  379. CinemachineCore.Instance.CurrentUpdateFilter = updateFilter;
  380. Camera camera = OutputCamera;
  381. CinemachineCore.Instance.UpdateAllActiveVirtualCameras(
  382. camera == null ? -1 : camera.cullingMask, DefaultWorldUp, deltaTime);
  383. // Make sure all live cameras get updated, in case some of them are deactivated
  384. if (SoloCamera != null)
  385. SoloCamera.UpdateCameraState(DefaultWorldUp, deltaTime);
  386. mCurrentLiveCameras.UpdateCameraState(DefaultWorldUp, deltaTime);
  387. // Restore the filter for general use
  388. updateFilter = CinemachineCore.UpdateFilter.Late;
  389. if (Application.isPlaying)
  390. {
  391. if (m_UpdateMethod == UpdateMethod.SmartUpdate)
  392. updateFilter |= CinemachineCore.UpdateFilter.Smart;
  393. else if (m_UpdateMethod == UpdateMethod.FixedUpdate)
  394. updateFilter = CinemachineCore.UpdateFilter.Fixed;
  395. }
  396. CinemachineCore.Instance.CurrentUpdateFilter = updateFilter;
  397. }
  398. /// <summary>
  399. /// Get the current active virtual camera.
  400. /// </summary>
  401. public ICinemachineCamera ActiveVirtualCamera
  402. {
  403. get
  404. {
  405. if (SoloCamera != null)
  406. return SoloCamera;
  407. return DeepCamBFromBlend(mCurrentLiveCameras);
  408. }
  409. }
  410. static ICinemachineCamera DeepCamBFromBlend(CinemachineBlend blend)
  411. {
  412. ICinemachineCamera vcam = blend.CamB;
  413. while (vcam != null)
  414. {
  415. if (!vcam.IsValid)
  416. return null; // deleted!
  417. BlendSourceVirtualCamera bs = vcam as BlendSourceVirtualCamera;
  418. if (bs == null)
  419. break;
  420. vcam = bs.Blend.CamB;
  421. }
  422. return vcam;
  423. }
  424. /// <summary>
  425. /// Is there a blend in progress?
  426. /// </summary>
  427. public bool IsBlending { get { return ActiveBlend != null; } }
  428. /// <summary>
  429. /// Get the current blend in progress. Returns null if none.
  430. /// </summary>
  431. public CinemachineBlend ActiveBlend
  432. {
  433. get
  434. {
  435. if (SoloCamera != null)
  436. return null;
  437. if (mCurrentLiveCameras.CamA == null || mCurrentLiveCameras.Equals(null) || mCurrentLiveCameras.IsComplete)
  438. return null;
  439. return mCurrentLiveCameras;
  440. }
  441. }
  442. private class BrainFrame
  443. {
  444. public int id;
  445. public CinemachineBlend blend = new CinemachineBlend(null, null, null, 0, 0);
  446. public bool Active { get { return blend.IsValid; } }
  447. // Working data - updated every frame
  448. public CinemachineBlend workingBlend = new CinemachineBlend(null, null, null, 0, 0);
  449. public BlendSourceVirtualCamera workingBlendSource = new BlendSourceVirtualCamera(null);
  450. // Used by Timeline Preview for overriding the current value of deltaTime
  451. public float deltaTimeOverride;
  452. }
  453. // Current game state is always frame 0, overrides are subsequent frames
  454. private List<BrainFrame> mFrameStack = new List<BrainFrame>();
  455. private int mNextFrameId = 1;
  456. /// Get the frame index corresponding to the ID
  457. private int GetBrainFrame(int withId)
  458. {
  459. int count = mFrameStack.Count;
  460. for (int i = mFrameStack.Count - 1; i > 0; --i)
  461. if (mFrameStack[i].id == withId)
  462. return i;
  463. // Not found - add it
  464. mFrameStack.Add(new BrainFrame() { id = withId });
  465. return mFrameStack.Count - 1;
  466. }
  467. // Current Brain State - result of all frames. Blend camB is "current" camera always
  468. CinemachineBlend mCurrentLiveCameras = new CinemachineBlend(null, null, null, 0, 0);
  469. // To avoid GC memory alloc every frame
  470. private static readonly AnimationCurve mDefaultLinearAnimationCurve = AnimationCurve.Linear(0, 0, 1, 1);
  471. /// <summary>
  472. /// This API is specifically for Timeline. Do not use it.
  473. /// Override the current camera and current blend. This setting will trump
  474. /// any in-game logic that sets virtual camera priorities and Enabled states.
  475. /// This is the main API for the timeline.
  476. /// </summary>
  477. /// <param name="overrideId">Id to represent a specific client. An internal
  478. /// stack is maintained, with the most recent non-empty override taking precenence.
  479. /// This id must be > 0. If you pass -1, a new id will be created, and returned.
  480. /// Use that id for subsequent calls. Don't forget to
  481. /// call ReleaseCameraOverride after all overriding is finished, to
  482. /// free the OverideStack resources.</param>
  483. /// <param name="camA"> The camera to set, corresponding to weight=0</param>
  484. /// <param name="camB"> The camera to set, corresponding to weight=1</param>
  485. /// <param name="weightB">The blend weight. 0=camA, 1=camB</param>
  486. /// <param name="deltaTime">override for deltaTime. Should be Time.FixedDelta for
  487. /// time-based calculations to be included, -1 otherwise</param>
  488. /// <returns>The oiverride ID. Don't forget to call ReleaseCameraOverride
  489. /// after all overriding is finished, to free the OverideStack resources.</returns>
  490. public int SetCameraOverride(
  491. int overrideId,
  492. ICinemachineCamera camA, ICinemachineCamera camB,
  493. float weightB, float deltaTime)
  494. {
  495. if (overrideId < 0)
  496. overrideId = mNextFrameId++;
  497. BrainFrame frame = mFrameStack[GetBrainFrame(overrideId)];
  498. frame.deltaTimeOverride = deltaTime;
  499. frame.blend.CamA = camA;
  500. frame.blend.CamB = camB;
  501. frame.blend.BlendCurve = mDefaultLinearAnimationCurve;
  502. frame.blend.Duration = 1;
  503. frame.blend.TimeInBlend = weightB;
  504. // In case vcams are inactive game objects, make sure they get initialized properly
  505. var cam = camA as CinemachineVirtualCameraBase;
  506. if (cam != null)
  507. cam.EnsureStarted();
  508. cam = camB as CinemachineVirtualCameraBase;
  509. if (cam != null)
  510. cam.EnsureStarted();
  511. return overrideId;
  512. }
  513. /// <summary>
  514. /// This API is specifically for Timeline. Do not use it.
  515. /// Release the resources used for a camera override client.
  516. /// See SetCameraOverride.
  517. /// </summary>
  518. /// <param name="overrideId">The ID to released. This is the value that
  519. /// was returned by SetCameraOverride</param>
  520. public void ReleaseCameraOverride(int overrideId)
  521. {
  522. for (int i = mFrameStack.Count - 1; i > 0; --i)
  523. {
  524. if (mFrameStack[i].id == overrideId)
  525. {
  526. mFrameStack.RemoveAt(i);
  527. return;
  528. }
  529. }
  530. }
  531. ICinemachineCamera mActiveCameraPreviousFrame;
  532. private void ProcessActiveCamera(float deltaTime)
  533. {
  534. var activeCamera = ActiveVirtualCamera;
  535. if (activeCamera != null)
  536. {
  537. // Has the current camera changed this frame?
  538. if (activeCamera != mActiveCameraPreviousFrame)
  539. {
  540. // Notify incoming camera of transition
  541. activeCamera.OnTransitionFromCamera(
  542. mActiveCameraPreviousFrame, DefaultWorldUp, deltaTime);
  543. if (m_CameraActivatedEvent != null)
  544. m_CameraActivatedEvent.Invoke(activeCamera, mActiveCameraPreviousFrame);
  545. // If we're cutting without a blend, send an event
  546. if (!IsBlending || (mActiveCameraPreviousFrame != null
  547. && !ActiveBlend.Uses(mActiveCameraPreviousFrame)))
  548. {
  549. if (m_CameraCutEvent != null)
  550. m_CameraCutEvent.Invoke(this);
  551. if (CinemachineCore.CameraCutEvent != null)
  552. CinemachineCore.CameraCutEvent.Invoke(this);
  553. }
  554. // Re-update in case it's inactive
  555. activeCamera.UpdateCameraState(DefaultWorldUp, deltaTime);
  556. }
  557. // Apply the vcam state to the Unity camera
  558. PushStateToUnityCamera(
  559. SoloCamera != null ? SoloCamera.State : mCurrentLiveCameras.State);
  560. }
  561. mActiveCameraPreviousFrame = activeCamera;
  562. }
  563. private void UpdateFrame0(float deltaTime)
  564. {
  565. // Update the in-game frame (frame 0)
  566. BrainFrame frame = mFrameStack[0];
  567. // Are we transitioning cameras?
  568. var activeCamera = TopCameraFromPriorityQueue();
  569. var outGoingCamera = frame.blend.CamB;
  570. if (activeCamera != outGoingCamera)
  571. {
  572. // Do we need to create a game-play blend?
  573. if ((UnityEngine.Object)activeCamera != null
  574. && (UnityEngine.Object)outGoingCamera != null && deltaTime >= 0)
  575. {
  576. // Create a blend (curve will be null if a cut)
  577. var blendDef = LookupBlend(outGoingCamera, activeCamera);
  578. if (blendDef.BlendCurve != null && blendDef.BlendTime > 0)
  579. {
  580. if (frame.blend.IsComplete)
  581. frame.blend.CamA = outGoingCamera; // new blend
  582. else
  583. {
  584. // Special case: if backing out of a blend-in-progress
  585. // with the same blend in reverse, adjust the blend time
  586. if ((frame.blend.CamA == activeCamera
  587. || (frame.blend.CamA as BlendSourceVirtualCamera)?.Blend.CamB == activeCamera)
  588. && frame.blend.CamB == outGoingCamera
  589. && frame.blend.Duration <= blendDef.BlendTime)
  590. {
  591. blendDef.m_Time =
  592. (frame.blend.TimeInBlend / frame.blend.Duration) * blendDef.BlendTime;
  593. }
  594. // Chain to existing blend
  595. frame.blend.CamA = new BlendSourceVirtualCamera(
  596. new CinemachineBlend(
  597. frame.blend.CamA, frame.blend.CamB,
  598. frame.blend.BlendCurve, frame.blend.Duration,
  599. frame.blend.TimeInBlend));
  600. }
  601. }
  602. frame.blend.BlendCurve = blendDef.BlendCurve;
  603. frame.blend.Duration = blendDef.BlendTime;
  604. frame.blend.TimeInBlend = 0;
  605. }
  606. // Set the current active camera
  607. frame.blend.CamB = activeCamera;
  608. }
  609. // Advance the current blend (if any)
  610. if (frame.blend.CamA != null)
  611. {
  612. frame.blend.TimeInBlend += (deltaTime >= 0) ? deltaTime : frame.blend.Duration;
  613. if (frame.blend.IsComplete)
  614. {
  615. // No more blend
  616. frame.blend.CamA = null;
  617. frame.blend.BlendCurve = null;
  618. frame.blend.Duration = 0;
  619. frame.blend.TimeInBlend = 0;
  620. }
  621. }
  622. }
  623. /// <summary>
  624. /// Used internally to compute the currrent blend, taking into account
  625. /// the in-game camera and all the active overrides. Caller may optionally
  626. /// exclude n topmost overrides.
  627. /// </summary>
  628. /// <param name="outputBlend">Receives the nested blend</param>
  629. /// <param name="numTopLayersToExclude">Optionaly exclude the last number
  630. /// of overrides from the blend</param>
  631. public void ComputeCurrentBlend(
  632. ref CinemachineBlend outputBlend, int numTopLayersToExclude)
  633. {
  634. // Resolve the current working frame states in the stack
  635. int lastActive = 0;
  636. int topLayer = Mathf.Max(1, mFrameStack.Count - numTopLayersToExclude);
  637. for (int i = 0; i < topLayer; ++i)
  638. {
  639. BrainFrame frame = mFrameStack[i];
  640. if (i == 0 || frame.Active)
  641. {
  642. frame.workingBlend.CamA = frame.blend.CamA;
  643. frame.workingBlend.CamB = frame.blend.CamB;
  644. frame.workingBlend.BlendCurve = frame.blend.BlendCurve;
  645. frame.workingBlend.Duration = frame.blend.Duration;
  646. frame.workingBlend.TimeInBlend = frame.blend.TimeInBlend;
  647. if (i > 0 && !frame.blend.IsComplete)
  648. {
  649. if (frame.workingBlend.CamA == null)
  650. {
  651. if (mFrameStack[lastActive].blend.IsComplete)
  652. frame.workingBlend.CamA = mFrameStack[lastActive].blend.CamB;
  653. else
  654. {
  655. frame.workingBlendSource.Blend = mFrameStack[lastActive].workingBlend;
  656. frame.workingBlend.CamA = frame.workingBlendSource;
  657. }
  658. }
  659. else if (frame.workingBlend.CamB == null)
  660. {
  661. if (mFrameStack[lastActive].blend.IsComplete)
  662. frame.workingBlend.CamB = mFrameStack[lastActive].blend.CamB;
  663. else
  664. {
  665. frame.workingBlendSource.Blend = mFrameStack[lastActive].workingBlend;
  666. frame.workingBlend.CamB = frame.workingBlendSource;
  667. }
  668. }
  669. }
  670. lastActive = i;
  671. }
  672. }
  673. var workingBlend = mFrameStack[lastActive].workingBlend;
  674. outputBlend.CamA = workingBlend.CamA;
  675. outputBlend.CamB = workingBlend.CamB;
  676. outputBlend.BlendCurve = workingBlend.BlendCurve;
  677. outputBlend.Duration = workingBlend.Duration;
  678. outputBlend.TimeInBlend = workingBlend.TimeInBlend;
  679. }
  680. /// <summary>
  681. /// True if the ICinemachineCamera the current active camera,
  682. /// or part of a current blend, either directly or indirectly because its parents are live.
  683. /// </summary>
  684. /// <param name="vcam">The camera to test whether it is live</param>
  685. /// <param name="dominantChildOnly">If truw, will only return true if this vcam is the dominat live child</param>
  686. /// <returns>True if the camera is live (directly or indirectly)
  687. /// or part of a blend in progress.</returns>
  688. public bool IsLive(ICinemachineCamera vcam, bool dominantChildOnly = false)
  689. {
  690. if (SoloCamera == vcam)
  691. return true;
  692. if (mCurrentLiveCameras.Uses(vcam))
  693. return true;
  694. ICinemachineCamera parent = vcam.ParentCamera;
  695. while (parent != null && parent.IsLiveChild(vcam, dominantChildOnly))
  696. {
  697. if (SoloCamera == parent || mCurrentLiveCameras.Uses(parent))
  698. return true;
  699. vcam = parent;
  700. parent = vcam.ParentCamera;
  701. }
  702. return false;
  703. }
  704. /// <summary>
  705. /// The current state applied to the unity camera (may be the result of a blend)
  706. /// </summary>
  707. public CameraState CurrentCameraState { get; private set; }
  708. /// <summary>
  709. /// Get the highest-priority Enabled ICinemachineCamera
  710. /// that is visible to my camera. Culling Mask is used to test visibility.
  711. /// </summary>
  712. private ICinemachineCamera TopCameraFromPriorityQueue()
  713. {
  714. CinemachineCore core = CinemachineCore.Instance;
  715. Camera outputCamera = OutputCamera;
  716. int mask = outputCamera == null ? ~0 : outputCamera.cullingMask;
  717. int numCameras = core.VirtualCameraCount;
  718. for (int i = 0; i < numCameras; ++i)
  719. {
  720. var cam = core.GetVirtualCamera(i);
  721. GameObject go = cam != null ? cam.gameObject : null;
  722. if (go != null && (mask & (1 << go.layer)) != 0)
  723. return cam;
  724. }
  725. return null;
  726. }
  727. /// <summary>
  728. /// Create a blend curve for blending from one ICinemachineCamera to another.
  729. /// If there is a specific blend defined for these cameras it will be used, otherwise
  730. /// a default blend will be created, which could be a cut.
  731. /// </summary>
  732. private CinemachineBlendDefinition LookupBlend(
  733. ICinemachineCamera fromKey, ICinemachineCamera toKey)
  734. {
  735. // Get the blend curve that's most appropriate for these cameras
  736. CinemachineBlendDefinition blend = m_DefaultBlend;
  737. if (m_CustomBlends != null)
  738. {
  739. string fromCameraName = (fromKey != null) ? fromKey.Name : string.Empty;
  740. string toCameraName = (toKey != null) ? toKey.Name : string.Empty;
  741. blend = m_CustomBlends.GetBlendForVirtualCameras(
  742. fromCameraName, toCameraName, blend);
  743. }
  744. if (CinemachineCore.GetBlendOverride != null)
  745. blend = CinemachineCore.GetBlendOverride(fromKey, toKey, blend, this);
  746. return blend;
  747. }
  748. /// <summary> Apply a cref="CameraState"/> to the game object</summary>
  749. private void PushStateToUnityCamera(CameraState state)
  750. {
  751. CurrentCameraState = state;
  752. if ((state.BlendHint & CameraState.BlendHintValue.NoPosition) == 0)
  753. transform.position = state.FinalPosition;
  754. if ((state.BlendHint & CameraState.BlendHintValue.NoOrientation) == 0)
  755. transform.rotation = state.FinalOrientation;
  756. if ((state.BlendHint & CameraState.BlendHintValue.NoLens) == 0)
  757. {
  758. Camera cam = OutputCamera;
  759. if (cam != null)
  760. {
  761. cam.nearClipPlane = state.Lens.NearClipPlane;
  762. cam.farClipPlane = state.Lens.FarClipPlane;
  763. cam.fieldOfView = state.Lens.FieldOfView;
  764. if (cam.orthographic)
  765. cam.orthographicSize = state.Lens.OrthographicSize;
  766. #if UNITY_2018_2_OR_NEWER
  767. else
  768. {
  769. cam.usePhysicalProperties = state.Lens.IsPhysicalCamera;
  770. cam.lensShift = state.Lens.LensShift;
  771. }
  772. #if CINEMACHINE_HDRP
  773. if (state.Lens.IsPhysicalCamera)
  774. {
  775. #if UNITY_2019_2_OR_NEWER
  776. cam.TryGetComponent<HDAdditionalCameraData>(out var hda);
  777. #else
  778. var hda = cam.GetComponent<HDAdditionalCameraData>();
  779. #endif
  780. if (hda != null)
  781. {
  782. hda.physicalParameters.iso = state.Lens.Iso;
  783. hda.physicalParameters.shutterSpeed = state.Lens.ShutterSpeed;
  784. hda.physicalParameters.aperture = state.Lens.Aperture;
  785. hda.physicalParameters.bladeCount = state.Lens.BladeCount;
  786. hda.physicalParameters.curvature = state.Lens.Curvature;
  787. hda.physicalParameters.barrelClipping = state.Lens.BarrelClipping;
  788. hda.physicalParameters.anamorphism = state.Lens.Anamorphism;
  789. }
  790. }
  791. #endif
  792. #endif
  793. }
  794. }
  795. if (CinemachineCore.CameraUpdatedEvent != null)
  796. CinemachineCore.CameraUpdatedEvent.Invoke(this);
  797. }
  798. }
  799. }