CinemachineVirtualCamera.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Serialization;
  4. namespace Cinemachine
  5. {
  6. /// <summary>
  7. /// This behaviour is intended to be attached to an empty Transform GameObject,
  8. /// and it represents a Virtual Camera within the Unity scene.
  9. ///
  10. /// The Virtual Camera will animate its Transform according to the rules contained
  11. /// in its CinemachineComponent pipeline (Aim, Body, and Noise). When the virtual
  12. /// camera is Live, the Unity camera will assume the position and orientation
  13. /// of the virtual camera.
  14. ///
  15. /// A virtual camera is not a camera. Instead, it can be thought of as a camera controller,
  16. /// not unlike a cameraman. It can drive the Unity Camera and control its position,
  17. /// orientation, lens settings, and PostProcessing effects. Each Virtual Camera owns
  18. /// its own Cinemachine Component Pipeline, through which you provide the instructions
  19. /// for dynamically tracking specific game objects.
  20. ///
  21. /// A virtual camera is very lightweight, and does no rendering of its own. It merely
  22. /// tracks interesting GameObjects, and positions itself accordingly. A typical game
  23. /// can have dozens of virtual cameras, each set up to follow a particular character
  24. /// or capture a particular event.
  25. ///
  26. /// A Virtual Camera can be in any of three states:
  27. ///
  28. /// * **Live**: The virtual camera is actively controlling the Unity Camera. The
  29. /// virtual camera is tracking its targets and being updated every frame.
  30. /// * **Standby**: The virtual camera is tracking its targets and being updated
  31. /// every frame, but no Unity Camera is actively being controlled by it. This is
  32. /// the state of a virtual camera that is enabled in the scene but perhaps at a
  33. /// lower priority than the Live virtual camera.
  34. /// * **Disabled**: The virtual camera is present but disabled in the scene. It is
  35. /// not actively tracking its targets and so consumes no processing power. However,
  36. /// the virtual camera can be made live from the Timeline.
  37. ///
  38. /// The Unity Camera can be driven by any virtual camera in the scene. The game
  39. /// logic can choose the virtual camera to make live by manipulating the virtual
  40. /// cameras' enabled flags and their priorities, based on game logic.
  41. ///
  42. /// In order to be driven by a virtual camera, the Unity Camera must have a CinemachineBrain
  43. /// behaviour, which will select the most eligible virtual camera based on its priority
  44. /// or on other criteria, and will manage blending.
  45. /// </summary>
  46. /// <seealso cref="CinemachineVirtualCameraBase"/>
  47. /// <seealso cref="LensSettings"/>
  48. /// <seealso cref="CinemachineComposer"/>
  49. /// <seealso cref="CinemachineTransposer"/>
  50. /// <seealso cref="CinemachineBasicMultiChannelPerlin"/>
  51. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  52. [DisallowMultipleComponent]
  53. #if UNITY_2018_3_OR_NEWER
  54. [ExecuteAlways]
  55. #else
  56. [ExecuteInEditMode]
  57. #endif
  58. [ExcludeFromPreset]
  59. [AddComponentMenu("Cinemachine/CinemachineVirtualCamera")]
  60. [HelpURL(Documentation.BaseURL + "manual/CinemachineVirtualCamera.html")]
  61. public class CinemachineVirtualCamera : CinemachineVirtualCameraBase
  62. {
  63. /// <summary>The object that the camera wants to look at (the Aim target).
  64. /// The Aim component of the CinemachineComponent pipeline
  65. /// will refer to this target and orient the vcam in accordance with rules and
  66. /// settings that are provided to it.
  67. /// If this is null, then the vcam's Transform orientation will be used.</summary>
  68. [Tooltip("The object that the camera wants to look at (the Aim target). "
  69. + "If this is null, then the vcam's Transform orientation will define the camera's orientation.")]
  70. [NoSaveDuringPlay]
  71. [VcamTargetProperty]
  72. public Transform m_LookAt = null;
  73. /// <summary>The object that the camera wants to move with (the Body target).
  74. /// The Body component of the CinemachineComponent pipeline
  75. /// will refer to this target and position the vcam in accordance with rules and
  76. /// settings that are provided to it.
  77. /// If this is null, then the vcam's Transform position will be used.</summary>
  78. [Tooltip("The object that the camera wants to move with (the Body target). "
  79. + "If this is null, then the vcam's Transform position will define the camera's position.")]
  80. [NoSaveDuringPlay]
  81. [VcamTargetProperty]
  82. public Transform m_Follow = null;
  83. /// <summary>Specifies the LensSettings of this Virtual Camera.
  84. /// These settings will be transferred to the Unity camera when the vcam is live.</summary>
  85. [FormerlySerializedAs("m_LensAttributes")]
  86. [Tooltip("Specifies the lens properties of this Virtual Camera. This generally mirrors the "
  87. + "Unity Camera's lens settings, and will be used to drive the Unity camera when the vcam is active.")]
  88. [LensSettingsProperty]
  89. public LensSettings m_Lens = LensSettings.Default;
  90. /// <summary> Collection of parameters that influence how this virtual camera transitions from
  91. /// other virtual cameras </summary>
  92. public TransitionParams m_Transitions;
  93. /// <summary>Legacy support</summary>
  94. [SerializeField] [HideInInspector]
  95. [FormerlySerializedAs("m_BlendHint")]
  96. [FormerlySerializedAs("m_PositionBlending")] private BlendHint m_LegacyBlendHint;
  97. /// <summary>This is the name of the hidden GameObject that will be created as a child object
  98. /// of the virtual camera. This hidden game object acts as a container for the polymorphic
  99. /// CinemachineComponent pipeline. The Inspector UI for the Virtual Camera
  100. /// provides access to this pipleline, as do the CinemachineComponent-family of
  101. /// public methods in this class.
  102. /// The lifecycle of the pipeline GameObject is managed automatically.</summary>
  103. public const string PipelineName = "cm";
  104. /// <summary>The CameraState object holds all of the information
  105. /// necessary to position the Unity camera. It is the output of this class.</summary>
  106. override public CameraState State { get { return m_State; } }
  107. /// <summary>Get the LookAt target for the Aim component in the Cinemachine pipeline.
  108. /// If this vcam is a part of a meta-camera collection, then the owner's target
  109. /// will be used if the local target is null.</summary>
  110. override public Transform LookAt
  111. {
  112. get { return ResolveLookAt(m_LookAt); }
  113. set { m_LookAt = value; }
  114. }
  115. /// <summary>Get the Follow target for the Body component in the Cinemachine pipeline.
  116. /// If this vcam is a part of a meta-camera collection, then the owner's target
  117. /// will be used if the local target is null.</summary>
  118. override public Transform Follow
  119. {
  120. get { return ResolveFollow(m_Follow); }
  121. set { m_Follow = value; }
  122. }
  123. /// <summary>
  124. /// Query components and extensions for the maximum damping time.
  125. /// </summary>
  126. /// <returns>Highest damping setting in this vcam</returns>
  127. public override float GetMaxDampTime()
  128. {
  129. float maxDamp = base.GetMaxDampTime();
  130. UpdateComponentPipeline();
  131. if (m_ComponentPipeline != null)
  132. for (int i = 0; i < m_ComponentPipeline.Length; ++i)
  133. maxDamp = Mathf.Max(maxDamp, m_ComponentPipeline[i].GetMaxDampTime());
  134. return maxDamp;
  135. }
  136. /// <summary>Internal use only. Do not call this method.
  137. /// Called by CinemachineCore at the appropriate Update time
  138. /// so the vcam can position itself and track its targets. This class will
  139. /// invoke its pipeline and generate a CameraState for this frame.</summary>
  140. /// <param name="worldUp">Effective world up</param>
  141. /// <param name="deltaTime">Effective deltaTime</param>
  142. override public void InternalUpdateCameraState(Vector3 worldUp, float deltaTime)
  143. {
  144. // Update the state by invoking the component pipeline
  145. m_State = CalculateNewState(worldUp, deltaTime);
  146. ApplyPositionBlendMethod(ref m_State, m_Transitions.m_BlendHint);
  147. // Push the raw position back to the game object's transform, so it
  148. // moves along with the camera.
  149. if (!UserIsDragging)
  150. {
  151. if (Follow != null)
  152. transform.position = State.RawPosition;
  153. if (LookAt != null)
  154. transform.rotation = State.RawOrientation;
  155. }
  156. PreviousStateIsValid = true;
  157. }
  158. /// <summary>Make sure that the pipeline cache is up-to-date.</summary>
  159. override protected void OnEnable()
  160. {
  161. base.OnEnable();
  162. m_State = PullStateFromVirtualCamera(Vector3.up, ref m_Lens);
  163. InvalidateComponentPipeline();
  164. // Can't add components during OnValidate
  165. if (ValidatingStreamVersion < 20170927)
  166. {
  167. if (Follow != null && GetCinemachineComponent(CinemachineCore.Stage.Body) == null)
  168. AddCinemachineComponent<CinemachineHardLockToTarget>();
  169. if (LookAt != null && GetCinemachineComponent(CinemachineCore.Stage.Aim) == null)
  170. AddCinemachineComponent<CinemachineHardLookAt>();
  171. }
  172. }
  173. /// <summary>Calls the DestroyPipelineDelegate for destroying the hidden
  174. /// child object, to support undo.</summary>
  175. protected override void OnDestroy()
  176. {
  177. // Make the pipeline visible instead of destroying - this is to keep Undo happy
  178. foreach (Transform child in transform)
  179. if (child.GetComponent<CinemachinePipeline>() != null)
  180. child.gameObject.hideFlags
  181. &= ~(HideFlags.HideInHierarchy | HideFlags.HideInInspector);
  182. base.OnDestroy();
  183. }
  184. /// <summary>Enforce bounds for fields, when changed in inspector.</summary>
  185. protected override void OnValidate()
  186. {
  187. base.OnValidate();
  188. m_Lens.Validate();
  189. if (m_LegacyBlendHint != BlendHint.None)
  190. {
  191. m_Transitions.m_BlendHint = m_LegacyBlendHint;
  192. m_LegacyBlendHint = BlendHint.None;
  193. }
  194. }
  195. void OnTransformChildrenChanged()
  196. {
  197. InvalidateComponentPipeline();
  198. }
  199. void Reset()
  200. {
  201. #if UNITY_EDITOR
  202. if (UnityEditor.PrefabUtility.GetPrefabInstanceStatus(gameObject)
  203. != UnityEditor.PrefabInstanceStatus.NotAPrefab)
  204. {
  205. Debug.Log("You cannot reset a prefab instance. "
  206. + "First disconnect this instance from the prefab, or enter Prefab Edit mode");
  207. return;
  208. }
  209. #endif
  210. DestroyPipeline();
  211. }
  212. /// <summary>
  213. /// Override component pipeline creation.
  214. /// This needs to be done by the editor to support Undo.
  215. /// The override must do exactly the same thing as the CreatePipeline method in this class.
  216. /// </summary>
  217. public static CreatePipelineDelegate CreatePipelineOverride;
  218. /// <summary>
  219. /// Override component pipeline creation.
  220. /// This needs to be done by the editor to support Undo.
  221. /// The override must do exactly the same thing as the CreatePipeline method in
  222. /// the CinemachineVirtualCamera class.
  223. /// </summary>
  224. public delegate Transform CreatePipelineDelegate(
  225. CinemachineVirtualCamera vcam, string name, CinemachineComponentBase[] copyFrom);
  226. /// <summary>
  227. /// Override component pipeline destruction.
  228. /// This needs to be done by the editor to support Undo.
  229. /// </summary>
  230. public static DestroyPipelineDelegate DestroyPipelineOverride;
  231. /// <summary>
  232. /// Override component pipeline destruction.
  233. /// This needs to be done by the editor to support Undo.
  234. /// </summary>
  235. public delegate void DestroyPipelineDelegate(GameObject pipeline);
  236. /// <summary>Destroy any existing pipeline container.</summary>
  237. private void DestroyPipeline()
  238. {
  239. List<Transform> oldPipeline = new List<Transform>();
  240. foreach (Transform child in transform)
  241. if (child.GetComponent<CinemachinePipeline>() != null)
  242. oldPipeline.Add(child);
  243. if (!RuntimeUtility.IsPrefab(gameObject))
  244. {
  245. foreach (Transform child in oldPipeline)
  246. {
  247. if (DestroyPipelineOverride != null)
  248. DestroyPipelineOverride(child.gameObject);
  249. else
  250. Destroy(child.gameObject);
  251. }
  252. m_ComponentOwner = null;
  253. }
  254. PreviousStateIsValid = false;
  255. }
  256. /// <summary>Create a default pipeline container.
  257. /// Note: copyFrom only supported in Editor, not build</summary>
  258. private Transform CreatePipeline(CinemachineVirtualCamera copyFrom)
  259. {
  260. CinemachineComponentBase[] components = null;
  261. if (copyFrom != null)
  262. {
  263. copyFrom.InvalidateComponentPipeline(); // make sure it's up to date
  264. components = copyFrom.GetComponentPipeline();
  265. }
  266. Transform newPipeline = null;
  267. if (CreatePipelineOverride != null)
  268. newPipeline = CreatePipelineOverride(this, PipelineName, components);
  269. else
  270. {
  271. GameObject go = new GameObject(PipelineName);
  272. go.transform.parent = transform;
  273. go.AddComponent<CinemachinePipeline>();
  274. newPipeline = go.transform;
  275. }
  276. PreviousStateIsValid = false;
  277. return newPipeline;
  278. }
  279. /// <summary>
  280. /// Editor API: Call this when changing the pipeline from the editor.
  281. /// Will force a rebuild of the pipeline cache.
  282. /// </summary>
  283. public void InvalidateComponentPipeline() { m_ComponentPipeline = null; }
  284. /// <summary>Get the hidden CinemachinePipeline child object.</summary>
  285. /// <returns>The hidden CinemachinePipeline child object</returns>
  286. public Transform GetComponentOwner() { UpdateComponentPipeline(); return m_ComponentOwner; }
  287. /// <summary>Get the component pipeline owned by the hidden child pipline container.
  288. /// For most purposes, it is preferable to use the GetCinemachineComponent method.</summary>
  289. /// <returns>The component pipeline</returns>
  290. public CinemachineComponentBase[] GetComponentPipeline() { UpdateComponentPipeline(); return m_ComponentPipeline; }
  291. /// <summary>Get the component set for a specific stage.</summary>
  292. /// <param name="stage">The stage for which we want the component</param>
  293. /// <returns>The Cinemachine component for that stage, or null if not defined</returns>
  294. public CinemachineComponentBase GetCinemachineComponent(CinemachineCore.Stage stage)
  295. {
  296. CinemachineComponentBase[] components = GetComponentPipeline();
  297. if (components != null)
  298. foreach (var c in components)
  299. if (c.Stage == stage)
  300. return c;
  301. return null;
  302. }
  303. /// <summary>Get an existing component of a specific type from the cinemachine pipeline.</summary>
  304. /// <typeparam name="T">The type of component to get</typeparam>
  305. /// <returns>The component if it's present, or null</returns>
  306. public T GetCinemachineComponent<T>() where T : CinemachineComponentBase
  307. {
  308. CinemachineComponentBase[] components = GetComponentPipeline();
  309. if (components != null)
  310. foreach (var c in components)
  311. if (c is T)
  312. return c as T;
  313. return null;
  314. }
  315. /// <summary>Add a component to the cinemachine pipeline.
  316. /// Existing components at the new component's stage are removed</summary>
  317. /// <typeparam name="T">The type of component to add</typeparam>
  318. /// <returns>The new component</returns>
  319. public T AddCinemachineComponent<T>() where T : CinemachineComponentBase
  320. {
  321. // Get the existing components
  322. Transform owner = GetComponentOwner();
  323. if (owner == null)
  324. return null; // maybe it's a prefab
  325. CinemachineComponentBase[] components = owner.GetComponents<CinemachineComponentBase>();
  326. T component = owner.gameObject.AddComponent<T>();
  327. if (component != null && components != null)
  328. {
  329. // Remove the existing components at that stage
  330. CinemachineCore.Stage stage = component.Stage;
  331. for (int i = components.Length - 1; i >= 0; --i)
  332. {
  333. if (components[i].Stage == stage)
  334. {
  335. components[i].enabled = false;
  336. RuntimeUtility.DestroyObject(components[i]);
  337. }
  338. }
  339. }
  340. InvalidateComponentPipeline();
  341. return component;
  342. }
  343. /// <summary>Remove a component from the cinemachine pipeline if it's present.</summary>
  344. /// <typeparam name="T">The type of component to remove</typeparam>
  345. public void DestroyCinemachineComponent<T>() where T : CinemachineComponentBase
  346. {
  347. CinemachineComponentBase[] components = GetComponentPipeline();
  348. if (components != null)
  349. {
  350. foreach (var c in components)
  351. {
  352. if (c is T)
  353. {
  354. c.enabled = false;
  355. RuntimeUtility.DestroyObject(c);
  356. InvalidateComponentPipeline();
  357. }
  358. }
  359. }
  360. }
  361. /// <summary>API for the editor, to make the dragging of position handles behave better.</summary>
  362. public bool UserIsDragging { get; set; }
  363. CameraState m_State = CameraState.Default; // Current state this frame
  364. CinemachineComponentBase[] m_ComponentPipeline = null;
  365. [SerializeField][HideInInspector] private Transform m_ComponentOwner = null; // serialized to handle copy/paste
  366. void UpdateComponentPipeline()
  367. {
  368. bool isPrefab = RuntimeUtility.IsPrefab(gameObject);
  369. #if UNITY_EDITOR
  370. // Did we just get copy/pasted?
  371. if (m_ComponentOwner != null && m_ComponentOwner.parent != transform)
  372. {
  373. if (!isPrefab) // can't paste to a prefab
  374. {
  375. CinemachineVirtualCamera copyFrom = (m_ComponentOwner.parent != null)
  376. ? m_ComponentOwner.parent.gameObject.GetComponent<CinemachineVirtualCamera>() : null;
  377. DestroyPipeline();
  378. m_ComponentOwner = CreatePipeline(copyFrom);
  379. }
  380. }
  381. if (m_ComponentOwner != null)
  382. SetFlagsForHiddenChild(m_ComponentOwner.gameObject);
  383. #endif
  384. // Early out if we're up-to-date
  385. if (m_ComponentOwner != null && m_ComponentPipeline != null)
  386. return;
  387. m_ComponentOwner = null;
  388. List<CinemachineComponentBase> list = new List<CinemachineComponentBase>();
  389. foreach (Transform child in transform)
  390. {
  391. if (child.GetComponent<CinemachinePipeline>() != null)
  392. {
  393. m_ComponentOwner = child;
  394. CinemachineComponentBase[] components = child.GetComponents<CinemachineComponentBase>();
  395. foreach (CinemachineComponentBase c in components)
  396. if (c.enabled)
  397. list.Add(c);
  398. }
  399. }
  400. // Make sure we have a pipeline owner
  401. if (m_ComponentOwner == null && !isPrefab)
  402. m_ComponentOwner = CreatePipeline(null);
  403. // Make sure the pipeline stays hidden, even through prefab
  404. if (m_ComponentOwner != null)
  405. SetFlagsForHiddenChild(m_ComponentOwner.gameObject);
  406. if (m_ComponentOwner != null && m_ComponentOwner.gameObject != null)
  407. {
  408. // Sort the pipeline
  409. list.Sort((c1, c2) => (int)c1.Stage - (int)c2.Stage);
  410. m_ComponentPipeline = list.ToArray();
  411. }
  412. }
  413. static internal void SetFlagsForHiddenChild(GameObject child)
  414. {
  415. if (child != null)
  416. {
  417. if (CinemachineCore.sShowHiddenObjects)
  418. child.hideFlags &= ~(HideFlags.HideInHierarchy | HideFlags.HideInInspector);
  419. else
  420. child.hideFlags |= (HideFlags.HideInHierarchy | HideFlags.HideInInspector);
  421. }
  422. }
  423. private Transform mCachedLookAtTarget;
  424. private CinemachineVirtualCameraBase mCachedLookAtTargetVcam;
  425. private CameraState CalculateNewState(Vector3 worldUp, float deltaTime)
  426. {
  427. FollowTargetAttachment = 1;
  428. LookAtTargetAttachment = 1;
  429. // Initialize the camera state, in case the game object got moved in the editor
  430. CameraState state = PullStateFromVirtualCamera(worldUp, ref m_Lens);
  431. Transform lookAtTarget = LookAt;
  432. if (lookAtTarget != mCachedLookAtTarget)
  433. {
  434. mCachedLookAtTarget = lookAtTarget;
  435. mCachedLookAtTargetVcam = null;
  436. if (lookAtTarget != null)
  437. mCachedLookAtTargetVcam = lookAtTarget.GetComponent<CinemachineVirtualCameraBase>();
  438. }
  439. if (lookAtTarget != null)
  440. {
  441. if (mCachedLookAtTargetVcam != null)
  442. state.ReferenceLookAt = mCachedLookAtTargetVcam.State.FinalPosition;
  443. else
  444. state.ReferenceLookAt = TargetPositionCache.GetTargetPosition(lookAtTarget);
  445. }
  446. // Update the state by invoking the component pipeline
  447. UpdateComponentPipeline(); // avoid GetComponentPipeline() here because of GC
  448. // Extensions first
  449. InvokePrePipelineMutateCameraStateCallback(this, ref state, deltaTime);
  450. // Then components
  451. if (m_ComponentPipeline == null)
  452. {
  453. state.BlendHint |= CameraState.BlendHintValue.IgnoreLookAtTarget;
  454. for (var stage = CinemachineCore.Stage.Body; stage <= CinemachineCore.Stage.Finalize; ++stage)
  455. InvokePostPipelineStageCallback(this, stage, ref state, deltaTime);
  456. }
  457. else
  458. {
  459. for (int i = 0; i < m_ComponentPipeline.Length; ++i)
  460. m_ComponentPipeline[i].PrePipelineMutateCameraState(ref state, deltaTime);
  461. int componentIndex = 0;
  462. CinemachineComponentBase postAimBody = null;
  463. for (var stage = CinemachineCore.Stage.Body; stage <= CinemachineCore.Stage.Finalize; ++stage)
  464. {
  465. var c = componentIndex < m_ComponentPipeline.Length
  466. ? m_ComponentPipeline[componentIndex] : null;
  467. if (c != null && stage == c.Stage)
  468. {
  469. ++componentIndex;
  470. if (stage == CinemachineCore.Stage.Body && c.BodyAppliesAfterAim)
  471. {
  472. postAimBody = c;
  473. continue; // do the body stage of the pipeline after Aim
  474. }
  475. c.MutateCameraState(ref state, deltaTime);
  476. }
  477. InvokePostPipelineStageCallback(this, stage, ref state, deltaTime);
  478. if (stage == CinemachineCore.Stage.Aim)
  479. {
  480. if (c == null)
  481. state.BlendHint |= CameraState.BlendHintValue.IgnoreLookAtTarget;
  482. // If we have saved a Body for after Aim, do it now
  483. if (postAimBody != null)
  484. {
  485. postAimBody.MutateCameraState(ref state, deltaTime);
  486. InvokePostPipelineStageCallback(this, CinemachineCore.Stage.Body, ref state, deltaTime);
  487. }
  488. }
  489. }
  490. }
  491. return state;
  492. }
  493. /// <summary>This is called to notify the vcam that a target got warped,
  494. /// so that the vcam can update its internal state to make the camera
  495. /// also warp seamlessy.</summary>
  496. /// <param name="target">The object that was warped</param>
  497. /// <param name="positionDelta">The amount the target's position changed</param>
  498. public override void OnTargetObjectWarped(Transform target, Vector3 positionDelta)
  499. {
  500. if (target == Follow)
  501. {
  502. transform.position += positionDelta;
  503. m_State.RawPosition += positionDelta;
  504. }
  505. UpdateComponentPipeline(); // avoid GetComponentPipeline() here because of GC
  506. if (m_ComponentPipeline != null)
  507. {
  508. for (int i = 0; i < m_ComponentPipeline.Length; ++i)
  509. m_ComponentPipeline[i].OnTargetObjectWarped(target, positionDelta);
  510. }
  511. base.OnTargetObjectWarped(target, positionDelta);
  512. }
  513. /// <summary>
  514. /// Force the virtual camera to assume a given position and orientation
  515. /// </summary>
  516. /// <param name="pos">Worldspace pposition to take</param>
  517. /// <param name="rot">Worldspace orientation to take</param>
  518. public override void ForceCameraPosition(Vector3 pos, Quaternion rot)
  519. {
  520. PreviousStateIsValid = true;
  521. transform.position = pos;
  522. transform.rotation = rot;
  523. m_State.RawPosition = pos;
  524. m_State.RawOrientation = rot;
  525. UpdateComponentPipeline(); // avoid GetComponentPipeline() here because of GC
  526. if (m_ComponentPipeline != null)
  527. for (int i = 0; i < m_ComponentPipeline.Length; ++i)
  528. m_ComponentPipeline[i].ForceCameraPosition(pos, rot);
  529. base.ForceCameraPosition(pos, rot);
  530. }
  531. // This is a hack for FreeLook rigs - to be removed
  532. internal void SetStateRawPosition(Vector3 pos) { m_State.RawPosition = pos; }
  533. /// <summary>If we are transitioning from another vcam, grab the position from it.</summary>
  534. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  535. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  536. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  537. public override void OnTransitionFromCamera(
  538. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  539. {
  540. base.OnTransitionFromCamera(fromCam, worldUp, deltaTime);
  541. InvokeOnTransitionInExtensions(fromCam, worldUp, deltaTime);
  542. bool forceUpdate = false;
  543. if (m_Transitions.m_InheritPosition && fromCam != null)
  544. {
  545. transform.position = fromCam.State.FinalPosition;
  546. //transform.rotation = fromCam.State.RawOrientation;
  547. PreviousStateIsValid = false;
  548. forceUpdate = true;
  549. }
  550. UpdateComponentPipeline(); // avoid GetComponentPipeline() here because of GC
  551. if (m_ComponentPipeline != null)
  552. {
  553. for (int i = 0; i < m_ComponentPipeline.Length; ++i)
  554. if (m_ComponentPipeline[i].OnTransitionFromCamera(
  555. fromCam, worldUp, deltaTime, ref m_Transitions))
  556. forceUpdate = true;
  557. }
  558. if (forceUpdate)
  559. {
  560. InternalUpdateCameraState(worldUp, deltaTime);
  561. InternalUpdateCameraState(worldUp, deltaTime);
  562. }
  563. else
  564. UpdateCameraState(worldUp, deltaTime);
  565. if (m_Transitions.m_OnCameraLive != null)
  566. m_Transitions.m_OnCameraLive.Invoke(this, fromCam);
  567. }
  568. }
  569. }