CinemachineVirtualCameraBase.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. using System;
  2. using System.Collections.Generic;
  3. using Cinemachine.Utility;
  4. using UnityEngine;
  5. using UnityEngine.Serialization;
  6. namespace Cinemachine
  7. {
  8. /// <summary>
  9. /// Base class for a Monobehaviour that represents a Virtual Camera within the Unity scene.
  10. ///
  11. /// This is intended to be attached to an empty Transform GameObject.
  12. /// Inherited classes can be either standalone virtual cameras such
  13. /// as CinemachineVirtualCamera, or meta-cameras such as
  14. /// CinemachineClearShot or CinemachineFreeLook.
  15. ///
  16. /// A CinemachineVirtualCameraBase exposes a Priority property. When the behaviour is
  17. /// enabled in the game, the Virtual Camera is automatically placed in a queue
  18. /// maintained by the static CinemachineCore singleton.
  19. /// The queue is sorted by priority. When a Unity camera is equipped with a
  20. /// CinemachineBrain behaviour, the brain will choose the camera
  21. /// at the head of the queue. If you have multiple Unity cameras with CinemachineBrain
  22. /// behaviours (say in a split-screen context), then you can filter the queue by
  23. /// setting the culling flags on the virtual cameras. The culling mask of the
  24. /// Unity Camera will then act as a filter for the brain. Apart from this,
  25. /// there is nothing that prevents a virtual camera from controlling multiple
  26. /// Unity cameras simultaneously.
  27. /// </summary>
  28. [SaveDuringPlay]
  29. public abstract class CinemachineVirtualCameraBase : MonoBehaviour, ICinemachineCamera
  30. {
  31. /// <summary>Inspector control - Use for hiding sections of the Inspector UI.</summary>
  32. [HideInInspector, SerializeField, NoSaveDuringPlay]
  33. public string[] m_ExcludedPropertiesInInspector = new string[] { "m_Script" };
  34. /// <summary>Inspector control - Use for enabling sections of the Inspector UI.</summary>
  35. [HideInInspector, SerializeField, NoSaveDuringPlay]
  36. public CinemachineCore.Stage[] m_LockStageInInspector;
  37. /// <summary>Version that was last streamed, for upgrading legacy</summary>
  38. public int ValidatingStreamVersion
  39. {
  40. get { return m_OnValidateCalled ? m_ValidatingStreamVersion : CinemachineCore.kStreamingVersion; }
  41. private set { m_ValidatingStreamVersion = value; }
  42. }
  43. private int m_ValidatingStreamVersion = 0;
  44. private bool m_OnValidateCalled = false;
  45. [HideInInspector, SerializeField, NoSaveDuringPlay]
  46. private int m_StreamingVersion;
  47. /// <summary>The priority will determine which camera becomes active based on the
  48. /// state of other cameras and this camera. Higher numbers have greater priority.
  49. /// </summary>
  50. [NoSaveDuringPlay]
  51. [Tooltip("The priority will determine which camera becomes active based on the state of "
  52. + "other cameras and this camera. Higher numbers have greater priority.")]
  53. public int m_Priority = 10;
  54. /// <summary>
  55. /// This must be set every frame at the start of the pipeline to relax the virtual camera's
  56. /// attachment to the target. Range is 0...1.
  57. /// 1 is full attachment, and is the normal state.
  58. /// 0 is no attachment, and virtual camera will behave as if no Follow
  59. /// targets are set.
  60. /// </summary>
  61. public float FollowTargetAttachment { get; set; }
  62. /// <summary>
  63. /// This must be set every frame at the start of the pipeline to relax the virtual camera's
  64. /// attachment to the target. Range is 0...1.
  65. /// 1 is full attachment, and is the normal state.
  66. /// 0 is no attachment, and virtual camera will behave as if no LookAt
  67. /// targets are set.
  68. /// </summary>
  69. public float LookAtTargetAttachment { get; set; }
  70. /// <summary>
  71. /// How often to update a virtual camera when it is in Standby mode
  72. /// </summary>
  73. public enum StandbyUpdateMode
  74. {
  75. /// <summary>Only update if the virtual camera is Live</summary>
  76. Never,
  77. /// <summary>Update the virtual camera every frame, even when it is not Live</summary>
  78. Always,
  79. /// <summary>Update the virtual camera occasionally, the exact frequency depends
  80. /// on how many other virtual cameras are in Standby</summary>
  81. RoundRobin
  82. };
  83. /// <summary>When the virtual camera is not live, this is how often the virtual camera will
  84. /// be updated. Set this to tune for performance. Most of the time Never is fine, unless
  85. /// the virtual camera is doing shot evaluation.
  86. /// </summary>
  87. [Tooltip("When the virtual camera is not live, this is how often the virtual camera will be updated. "
  88. + "Set this to tune for performance. Most of the time Never is fine, "
  89. + "unless the virtual camera is doing shot evaluation.")]
  90. public StandbyUpdateMode m_StandbyUpdate = StandbyUpdateMode.RoundRobin;
  91. /// <summary>
  92. /// Query components and extensions for the maximum damping time.
  93. /// Base class implementation queries extensions.
  94. /// Only used in editor for timeline scrubbing.
  95. /// </summary>
  96. /// <returns>Highest damping setting in this vcam</returns>
  97. public virtual float GetMaxDampTime()
  98. {
  99. float maxDamp = 0;
  100. if (mExtensions != null)
  101. for (int i = 0; i < mExtensions.Count; ++i)
  102. maxDamp = Mathf.Max(maxDamp, mExtensions[i].GetMaxDampTime());
  103. return maxDamp;
  104. }
  105. /// <summary>Get a damped version of a quantity. This is the portion of the
  106. /// quantity that will take effect over the given time.
  107. /// This method takes the target attachment into account. For general
  108. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  109. /// <param name="initial">The amount that will be damped</param>
  110. /// <param name="dampTime">The rate of damping. This is the time it would
  111. /// take to reduce the original amount to a negligible percentage</param>
  112. /// <param name="deltaTime">The time over which to damp</param>
  113. /// <returns>The damped amount. This will be the original amount scaled by
  114. /// a value between 0 and 1.</returns>
  115. public float DetachedFollowTargetDamp(float initial, float dampTime, float deltaTime)
  116. {
  117. dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, FollowTargetAttachment);
  118. deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
  119. return Damper.Damp(initial, dampTime, deltaTime);
  120. }
  121. /// <summary>Get a damped version of a quantity. This is the portion of the
  122. /// quantity that will take effect over the given time.
  123. /// This method takes the target attachment into account. For general
  124. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  125. /// <param name="initial">The amount that will be damped</param>
  126. /// <param name="dampTime">The rate of damping. This is the time it would
  127. /// take to reduce the original amount to a negligible percentage</param>
  128. /// <param name="deltaTime">The time over which to damp</param>
  129. /// <returns>The damped amount. This will be the original amount scaled by
  130. /// a value between 0 and 1.</returns>
  131. public Vector3 DetachedFollowTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
  132. {
  133. dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, FollowTargetAttachment);
  134. deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
  135. return Damper.Damp(initial, dampTime, deltaTime);
  136. }
  137. /// <summary>Get a damped version of a quantity. This is the portion of the
  138. /// quantity that will take effect over the given time.
  139. /// This method takes the target attachment into account. For general
  140. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  141. /// <param name="initial">The amount that will be damped</param>
  142. /// <param name="dampTime">The rate of damping. This is the time it would
  143. /// take to reduce the original amount to a negligible percentage</param>
  144. /// <param name="deltaTime">The time over which to damp</param>
  145. /// <returns>The damped amount. This will be the original amount scaled by
  146. /// a value between 0 and 1.</returns>
  147. public Vector3 DetachedFollowTargetDamp(Vector3 initial, float dampTime, float deltaTime)
  148. {
  149. dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, FollowTargetAttachment);
  150. deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
  151. return Damper.Damp(initial, dampTime, deltaTime);
  152. }
  153. /// <summary>Get a damped version of a quantity. This is the portion of the
  154. /// quantity that will take effect over the given time.
  155. /// This method takes the target attachment into account. For general
  156. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  157. /// <param name="initial">The amount that will be damped</param>
  158. /// <param name="dampTime">The rate of damping. This is the time it would
  159. /// take to reduce the original amount to a negligible percentage</param>
  160. /// <param name="deltaTime">The time over which to damp</param>
  161. /// <returns>The damped amount. This will be the original amount scaled by
  162. /// a value between 0 and 1.</returns>
  163. public float DetachedLookAtTargetDamp(float initial, float dampTime, float deltaTime)
  164. {
  165. dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, LookAtTargetAttachment);
  166. deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
  167. return Damper.Damp(initial, dampTime, deltaTime);
  168. }
  169. /// <summary>Get a damped version of a quantity. This is the portion of the
  170. /// quantity that will take effect over the given time.
  171. /// This method takes the target attachment into account. For general
  172. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  173. /// <param name="initial">The amount that will be damped</param>
  174. /// <param name="dampTime">The rate of damping. This is the time it would
  175. /// take to reduce the original amount to a negligible percentage</param>
  176. /// <param name="deltaTime">The time over which to damp</param>
  177. /// <returns>The damped amount. This will be the original amount scaled by
  178. /// a value between 0 and 1.</returns>
  179. public Vector3 DetachedLookAtTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
  180. {
  181. dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, LookAtTargetAttachment);
  182. deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
  183. return Damper.Damp(initial, dampTime, deltaTime);
  184. }
  185. /// <summary>Get a damped version of a quantity. This is the portion of the
  186. /// quantity that will take effect over the given time.
  187. /// This method takes the target attachment into account. For general
  188. /// damping without consideration of target attachment, use Damper.Damp()</summary>
  189. /// <param name="initial">The amount that will be damped</param>
  190. /// <param name="dampTime">The rate of damping. This is the time it would
  191. /// take to reduce the original amount to a negligible percentage</param>
  192. /// <param name="deltaTime">The time over which to damp</param>
  193. /// <returns>The damped amount. This will be the original amount scaled by
  194. /// a value between 0 and 1.</returns>
  195. public Vector3 DetachedLookAtTargetDamp(Vector3 initial, float dampTime, float deltaTime)
  196. {
  197. dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, LookAtTargetAttachment);
  198. deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
  199. return Damper.Damp(initial, dampTime, deltaTime);
  200. }
  201. /// <summary>
  202. /// A delegate to hook into the state calculation pipeline.
  203. /// This will be called after each pipeline stage, to allow others to hook into the pipeline.
  204. /// See CinemachineCore.Stage.
  205. /// </summary>
  206. /// <param name="extension">The extension to add.</param>
  207. public virtual void AddExtension(CinemachineExtension extension)
  208. {
  209. if (mExtensions == null)
  210. mExtensions = new List<CinemachineExtension>();
  211. else
  212. mExtensions.Remove(extension);
  213. mExtensions.Add(extension);
  214. }
  215. /// <summary>Remove a Pipeline stage hook callback.</summary>
  216. /// <param name="extension">The extension to remove.</param>
  217. public virtual void RemoveExtension(CinemachineExtension extension)
  218. {
  219. if (mExtensions != null)
  220. mExtensions.Remove(extension);
  221. }
  222. /// <summary> Tee extensions connected to this vcam</summary>
  223. List<CinemachineExtension> mExtensions;
  224. /// <summary>
  225. /// Invokes the PostPipelineStageDelegate for this camera, and up the hierarchy for all
  226. /// parent cameras (if any).
  227. /// Implementaion must be sure to call this after each pipeline stage, to allow
  228. /// other services to hook into the pipeline.
  229. /// See CinemachineCore.Stage.
  230. /// </summary>
  231. /// <param name="vcam">The virtual camera being processed</param>
  232. /// <param name="stage">The current pipeline stage</param>
  233. /// <param name="newState">The current virtual camera state</param>
  234. /// <param name="deltaTime">The current applicable deltaTime</param>
  235. protected void InvokePostPipelineStageCallback(
  236. CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage,
  237. ref CameraState newState, float deltaTime)
  238. {
  239. if (mExtensions != null)
  240. {
  241. for (int i = 0; i < mExtensions.Count; ++i)
  242. {
  243. var e = mExtensions[i];
  244. if (e == null)
  245. {
  246. // Object was deleted (possibly because of Undo in the editor)
  247. mExtensions.RemoveAt(i);
  248. --i;
  249. }
  250. else if (e.enabled)
  251. e.InvokePostPipelineStageCallback(vcam, stage, ref newState, deltaTime);
  252. }
  253. }
  254. CinemachineVirtualCameraBase parent = ParentCamera as CinemachineVirtualCameraBase;
  255. if (parent != null)
  256. parent.InvokePostPipelineStageCallback(vcam, stage, ref newState, deltaTime);
  257. }
  258. /// <summary>
  259. /// Invokes the PrePipelineMutateCameraStateCallback for this camera,
  260. /// and up the hierarchy for all parent cameras (if any).
  261. /// Implementaion must be sure to call this after each pipeline stage, to allow
  262. /// other services to hook into the pipeline.
  263. /// See CinemachineCore.Stage.
  264. /// </summary>
  265. /// <param name="vcam">The virtual camera being processed</param>
  266. /// <param name="newState">The current virtual camera state</param>
  267. /// <param name="deltaTime">The current applicable deltaTime</param>
  268. protected void InvokePrePipelineMutateCameraStateCallback(
  269. CinemachineVirtualCameraBase vcam, ref CameraState newState, float deltaTime)
  270. {
  271. if (mExtensions != null)
  272. {
  273. for (int i = 0; i < mExtensions.Count; ++i)
  274. {
  275. var e = mExtensions[i];
  276. if (e == null)
  277. {
  278. // Object was deleted (possibly because of Undo in the editor)
  279. mExtensions.RemoveAt(i);
  280. --i;
  281. }
  282. else if (e.enabled)
  283. e.PrePipelineMutateCameraStateCallback(vcam, ref newState, deltaTime);
  284. }
  285. }
  286. CinemachineVirtualCameraBase parent = ParentCamera as CinemachineVirtualCameraBase;
  287. if (parent != null)
  288. parent.InvokePrePipelineMutateCameraStateCallback(vcam, ref newState, deltaTime);
  289. }
  290. /// <summary>
  291. /// Invokes the OnTransitionFromCamera for all extensions on this camera
  292. /// </summary>
  293. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  294. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  295. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  296. /// <returns>True to request a vcam update of internal state</returns>
  297. protected bool InvokeOnTransitionInExtensions(
  298. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  299. {
  300. bool forceUpdate = false;
  301. if (mExtensions != null)
  302. {
  303. for (int i = 0; i < mExtensions.Count; ++i)
  304. {
  305. var e = mExtensions[i];
  306. if (e == null)
  307. {
  308. // Object was deleted (possibly because of Undo in the editor)
  309. mExtensions.RemoveAt(i);
  310. --i;
  311. }
  312. else if (e.enabled && e.OnTransitionFromCamera(fromCam, worldUp, deltaTime))
  313. forceUpdate = true;
  314. }
  315. }
  316. return forceUpdate;
  317. }
  318. /// <summary>Get the name of the Virtual Camera. Base implementation
  319. /// returns the owner GameObject's name.</summary>
  320. public string Name { get { return name; } }
  321. /// <summary>Gets a brief debug description of this virtual camera, for use when displayiong debug info</summary>
  322. public virtual string Description { get { return ""; }}
  323. /// <summary>Get the Priority of the virtual camera. This determines its placement
  324. /// in the CinemachineCore's queue of eligible shots.</summary>
  325. public int Priority { get { return m_Priority; } set { m_Priority = value; } }
  326. /// <summary>Hint for blending to and from this virtual camera</summary>
  327. public enum BlendHint
  328. {
  329. /// <summary>Standard linear position and aim blend</summary>
  330. None,
  331. /// <summary>Spherical blend about LookAt target position if there is a LookAt target, linear blend between LookAt targets</summary>
  332. SphericalPosition,
  333. /// <summary>Cylindrical blend about LookAt target position if there is a LookAt target (vertical co-ordinate is linearly interpolated), linear blend between LookAt targets</summary>
  334. CylindricalPosition,
  335. /// <summary>Standard linear position blend, radial blend between LookAt targets</summary>
  336. ScreenSpaceAimWhenTargetsDiffer
  337. }
  338. /// <summary>Applies a position blend hint to the camera state</summary>
  339. protected void ApplyPositionBlendMethod(ref CameraState state, BlendHint hint)
  340. {
  341. switch (hint)
  342. {
  343. default:
  344. break;
  345. case BlendHint.SphericalPosition:
  346. state.BlendHint |= CameraState.BlendHintValue.SphericalPositionBlend;
  347. break;
  348. case BlendHint.CylindricalPosition:
  349. state.BlendHint |= CameraState.BlendHintValue.CylindricalPositionBlend;
  350. break;
  351. case BlendHint.ScreenSpaceAimWhenTargetsDiffer:
  352. state.BlendHint |= CameraState.BlendHintValue.RadialAimBlend;
  353. break;
  354. }
  355. }
  356. /// <summary>The GameObject owner of the Virtual Camera behaviour.</summary>
  357. public GameObject VirtualCameraGameObject
  358. {
  359. get
  360. {
  361. if (this == null)
  362. return null; // object deleted
  363. return gameObject;
  364. }
  365. }
  366. /// <summary>Returns false if the object has been deleted</summary>
  367. public bool IsValid { get { return !(this == null); } }
  368. /// <summary>The CameraState object holds all of the information
  369. /// necessary to position the Unity camera. It is the output of this class.</summary>
  370. public abstract CameraState State { get; }
  371. /// <summary>Support for meta-virtual-cameras. This is the situation where a
  372. /// virtual camera is in fact the public face of a private army of virtual cameras, which
  373. /// it manages on its own. This method gets the VirtualCamera owner, if any.
  374. /// Private armies are implemented as Transform children of the parent vcam.</summary>
  375. public ICinemachineCamera ParentCamera
  376. {
  377. get
  378. {
  379. if (!mSlaveStatusUpdated || !Application.isPlaying)
  380. UpdateSlaveStatus();
  381. return m_parentVcam;
  382. }
  383. }
  384. /// <summary>Check whether the vcam a live child of this camera.
  385. /// This base class implementation always returns false.</summary>
  386. /// <param name="vcam">The Virtual Camera to check</param>
  387. /// <param name="dominantChildOnly">If truw, will only return true if this vcam is the dominat live child</param>
  388. /// <returns>True if the vcam is currently actively influencing the state of this vcam</returns>
  389. public virtual bool IsLiveChild(ICinemachineCamera vcam, bool dominantChildOnly = false) { return false; }
  390. /// <summary>Get the LookAt target for the Aim component in the Cinemachine pipeline.</summary>
  391. public abstract Transform LookAt { get; set; }
  392. /// <summary>Get the Follow target for the Body component in the Cinemachine pipeline.</summary>
  393. public abstract Transform Follow { get; set; }
  394. /// <summary>Set this to force the next update to ignore deltaTime and reset itself</summary>
  395. public virtual bool PreviousStateIsValid { get; set; }
  396. /// <summary>
  397. /// Update the camera's state.
  398. /// The implementation must guarantee against multiple calls per frame, and should
  399. /// use CinemachineCore.UpdateVirtualCamera(ICinemachineCamera, Vector3, float), which
  400. /// has protection against multiple calls per frame.
  401. /// </summary>
  402. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  403. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
  404. public void UpdateCameraState(Vector3 worldUp, float deltaTime)
  405. {
  406. CinemachineCore.Instance.UpdateVirtualCamera(this, worldUp, deltaTime);
  407. }
  408. /// <summary>Internal use only. Do not call this method.
  409. /// Called by CinemachineCore at designated update time
  410. /// so the vcam can position itself and track its targets.
  411. /// Do not call this method. Let the framework do it at the appropriate time</summary>
  412. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  413. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
  414. public abstract void InternalUpdateCameraState(Vector3 worldUp, float deltaTime);
  415. /// <summary> Collection of parameters that influence how this virtual camera transitions from
  416. /// other virtual cameras </summary>
  417. [Serializable]
  418. public struct TransitionParams
  419. {
  420. /// <summary>Hint for blending positions to and from this virtual camera</summary>
  421. [Tooltip("Hint for blending positions to and from this virtual camera")]
  422. [FormerlySerializedAs("m_PositionBlending")]
  423. public BlendHint m_BlendHint;
  424. /// <summary>When this virtual camera goes Live, attempt to force the position to be the same as the current position of the Unity Camera</summary>
  425. [Tooltip("When this virtual camera goes Live, attempt to force the position to be the same as the current position of the Unity Camera")]
  426. public bool m_InheritPosition;
  427. /// <summary>This event fires when the virtual camera goes Live</summary>
  428. [Tooltip("This event fires when the virtual camera goes Live")]
  429. public CinemachineBrain.VcamActivatedEvent m_OnCameraLive;
  430. }
  431. /// <summary>Notification that this virtual camera is going live.
  432. /// Base class implementation must be called by any overridden method.</summary>
  433. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  434. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  435. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  436. public virtual void OnTransitionFromCamera(
  437. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  438. {
  439. if (!gameObject.activeInHierarchy)
  440. PreviousStateIsValid = false;
  441. }
  442. /// <summary>Maintains the global vcam registry. Always call the base class implementation.</summary>
  443. protected virtual void OnDestroy()
  444. {
  445. CinemachineCore.Instance.CameraDestroyed(this);
  446. }
  447. /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
  448. protected virtual void OnTransformParentChanged()
  449. {
  450. CinemachineCore.Instance.CameraDisabled(this);
  451. CinemachineCore.Instance.CameraEnabled(this);
  452. UpdateSlaveStatus();
  453. UpdateVcamPoolStatus();
  454. }
  455. bool m_WasStarted;
  456. /// <summary>Derived classes should call base class implementation.</summary>
  457. protected virtual void Start()
  458. {
  459. m_WasStarted = true;
  460. }
  461. /// <summary>
  462. /// Called on inactive object when being artificially activated by timeline.
  463. /// This is necessary because Awake() isn't called on inactive gameObjects.
  464. /// </summary>
  465. internal void EnsureStarted()
  466. {
  467. if (!m_WasStarted)
  468. {
  469. m_WasStarted = true;
  470. var extensions = GetComponentsInChildren<CinemachineExtension>();
  471. for (int i = 0; i < extensions.Length; ++i)
  472. extensions[i].EnsureStarted();
  473. }
  474. }
  475. /// <summary>
  476. /// Locate the first component that implements AxisState.IInputAxisProvider.
  477. /// </summary>
  478. /// <returns>The first AxisState.IInputAxisProvider or null if none</returns>
  479. public AxisState.IInputAxisProvider GetInputAxisProvider()
  480. {
  481. var components = GetComponentsInChildren<MonoBehaviour>();
  482. for (int i = 0; i < components.Length; ++i)
  483. {
  484. var provider = components[i] as AxisState.IInputAxisProvider;
  485. if (provider != null)
  486. return provider;
  487. }
  488. return null;
  489. }
  490. /// <summary>Enforce bounds for fields, when changed in inspector.
  491. /// Call base class implementation at the beginning of overridden method.
  492. /// After base method is called, ValidatingStreamVersion will be valid.</summary>
  493. protected virtual void OnValidate()
  494. {
  495. m_OnValidateCalled = true;
  496. ValidatingStreamVersion = m_StreamingVersion;
  497. m_StreamingVersion = CinemachineCore.kStreamingVersion;
  498. }
  499. /// <summary>Base class implementation adds the virtual camera from the priority queue.</summary>
  500. protected virtual void OnEnable()
  501. {
  502. UpdateSlaveStatus();
  503. UpdateVcamPoolStatus(); // Add to queue
  504. if (!CinemachineCore.Instance.IsLive(this))
  505. PreviousStateIsValid = false;
  506. CinemachineCore.Instance.CameraEnabled(this);
  507. // Sanity check - if another vcam component is enabled, shut down
  508. var vcamComponents = GetComponents<CinemachineVirtualCameraBase>();
  509. for (int i = 0; i < vcamComponents.Length; ++i)
  510. {
  511. if (vcamComponents[i].enabled && vcamComponents[i] != this)
  512. {
  513. Debug.LogError(Name
  514. + " has multiple CinemachineVirtualCameraBase-derived components. Disabling "
  515. + GetType().Name + ".");
  516. enabled = false;
  517. }
  518. }
  519. }
  520. /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
  521. protected virtual void OnDisable()
  522. {
  523. UpdateVcamPoolStatus(); // Remove from queue
  524. CinemachineCore.Instance.CameraDisabled(this);
  525. }
  526. /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
  527. protected virtual void Update()
  528. {
  529. if (m_Priority != m_QueuePriority)
  530. UpdateVcamPoolStatus();
  531. }
  532. private bool mSlaveStatusUpdated = false;
  533. private CinemachineVirtualCameraBase m_parentVcam = null;
  534. private void UpdateSlaveStatus()
  535. {
  536. mSlaveStatusUpdated = true;
  537. m_parentVcam = null;
  538. Transform p = transform.parent;
  539. if (p != null)
  540. {
  541. #if UNITY_2019_2_OR_NEWER
  542. p.TryGetComponent(out m_parentVcam);
  543. #else
  544. m_parentVcam = p.GetComponent<CinemachineVirtualCameraBase>();
  545. #endif
  546. }
  547. }
  548. /// <summary>Returns this vcam's LookAt target, or if that is null, will retrun
  549. /// the parent vcam's LookAt target.</summary>
  550. /// <param name="localLookAt">This vcam's LookAt value.</param>
  551. /// <returns>The same value, or the parent's if null and a parent exists.</returns>
  552. protected Transform ResolveLookAt(Transform localLookAt)
  553. {
  554. Transform lookAt = localLookAt;
  555. if (lookAt == null && ParentCamera != null)
  556. lookAt = ParentCamera.LookAt; // Parent provides default
  557. return lookAt;
  558. }
  559. /// <summary>Returns this vcam's Follow target, or if that is null, will retrun
  560. /// the parent vcam's Follow target.</summary>
  561. /// <param name="localFollow">This vcam's Follow value.</param>
  562. /// <returns>The same value, or the parent's if null and a parent exists.</returns>
  563. protected Transform ResolveFollow(Transform localFollow)
  564. {
  565. Transform follow = localFollow;
  566. if (follow == null && ParentCamera != null)
  567. follow = ParentCamera.Follow; // Parent provides default
  568. return follow;
  569. }
  570. private int m_QueuePriority = int.MaxValue;
  571. private void UpdateVcamPoolStatus()
  572. {
  573. CinemachineCore.Instance.RemoveActiveCamera(this);
  574. if (m_parentVcam == null && isActiveAndEnabled)
  575. CinemachineCore.Instance.AddActiveCamera(this);
  576. m_QueuePriority = m_Priority;
  577. }
  578. /// <summary>When multiple virtual cameras have the highest priority, there is
  579. /// sometimes the need to push one to the top, making it the current Live camera if
  580. /// it shares the highest priority in the queue with its peers.
  581. ///
  582. /// This happens automatically when a
  583. /// new vcam is enabled: the most recent one goes to the top of the priority subqueue.
  584. /// Use this method to push a vcam to the top of its priority peers.
  585. /// If it and its peers share the highest priority, then this vcam will become Live.</summary>
  586. public void MoveToTopOfPrioritySubqueue()
  587. {
  588. UpdateVcamPoolStatus();
  589. }
  590. /// <summary>This is called to notify the component that a target got warped,
  591. /// so that the component can update its internal state to make the camera
  592. /// also warp seamlessy.</summary>
  593. /// <param name="target">The object that was warped</param>
  594. /// <param name="positionDelta">The amount the target's position changed</param>
  595. public virtual void OnTargetObjectWarped(Transform target, Vector3 positionDelta)
  596. {
  597. // inform the extensions
  598. if (mExtensions != null)
  599. {
  600. for (int i = 0; i < mExtensions.Count; ++i)
  601. mExtensions[i].OnTargetObjectWarped(target, positionDelta);
  602. }
  603. }
  604. /// <summary>
  605. /// Force the virtual camera to assume a given position and orientation
  606. /// </summary>
  607. /// <param name="pos">Worldspace pposition to take</param>
  608. /// <param name="rot">Worldspace orientation to take</param>
  609. public virtual void ForceCameraPosition(Vector3 pos, Quaternion rot)
  610. {
  611. // inform the extensions
  612. if (mExtensions != null)
  613. {
  614. for (int i = 0; i < mExtensions.Count; ++i)
  615. mExtensions[i].ForceCameraPosition(pos, rot);
  616. }
  617. }
  618. /// <summary>Create a blend between 2 virtual cameras, taking into account
  619. /// any existing active blend.</summary>
  620. protected CinemachineBlend CreateBlend(
  621. ICinemachineCamera camA, ICinemachineCamera camB,
  622. CinemachineBlendDefinition blendDef,
  623. CinemachineBlend activeBlend)
  624. {
  625. if (blendDef.BlendCurve == null || blendDef.BlendTime <= 0 || (camA == null && camB == null))
  626. return null;
  627. if (activeBlend != null)
  628. {
  629. // Special case: if backing out of a blend-in-progress
  630. // with the same blend in reverse, adjust the belnd time
  631. if (activeBlend.CamA == camB
  632. && activeBlend.CamB == camA
  633. && activeBlend.Duration <= blendDef.BlendTime)
  634. {
  635. blendDef.m_Time = activeBlend.TimeInBlend;
  636. }
  637. camA = new BlendSourceVirtualCamera(activeBlend);
  638. }
  639. else if (camA == null)
  640. camA = new StaticPointVirtualCamera(State, "(none)");
  641. return new CinemachineBlend(
  642. camA, camB, blendDef.BlendCurve, blendDef.BlendTime, 0);
  643. }
  644. /// <summary>
  645. /// Create a camera state based on the current transform of this vcam
  646. /// </summary>
  647. /// <param name="worldUp">Current World Up direction, as provided by the brain</param>
  648. /// <param name="lens">Lens settings to serve as base, will be combined with lens from brain, if any</param>
  649. /// <returns></returns>
  650. protected CameraState PullStateFromVirtualCamera(Vector3 worldUp, ref LensSettings lens)
  651. {
  652. CameraState state = CameraState.Default;
  653. state.RawPosition = TargetPositionCache.GetTargetPosition(transform);
  654. state.RawOrientation = TargetPositionCache.GetTargetRotation(transform);
  655. state.ReferenceUp = worldUp;
  656. CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(this);
  657. if (brain != null)
  658. lens.SnapshotCameraReadOnlyProperties(brain.OutputCamera);
  659. state.Lens = lens;
  660. return state;
  661. }
  662. }
  663. }