CinemachineNewVirtualCamera.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #if CINEMACHINE_EXPERIMENTAL_VCAM
  2. using UnityEngine;
  3. using System;
  4. namespace Cinemachine
  5. {
  6. /// <summary>
  7. ///
  8. /// NOTE: THIS CLASS IS EXPERIMENTAL, AND NOT FOR PUBLIC USE
  9. ///
  10. /// Lighter-weight version of the CinemachineVirtualCamera.
  11. ///
  12. /// </summary>
  13. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  14. [DisallowMultipleComponent]
  15. #if UNITY_2018_3_OR_NEWER
  16. [ExecuteAlways]
  17. #else
  18. [ExecuteInEditMode]
  19. #endif
  20. [AddComponentMenu("Cinemachine/CinemachineNewVirtualCamera")]
  21. public class CinemachineNewVirtualCamera : CinemachineVirtualCameraBase
  22. {
  23. /// <summary>Object for the camera children to look at (the aim target)</summary>
  24. [Tooltip("Object for the camera children to look at (the aim target).")]
  25. [NoSaveDuringPlay]
  26. [VcamTargetProperty]
  27. public Transform m_LookAt = null;
  28. /// <summary>Object for the camera children wants to move with (the body target)</summary>
  29. [Tooltip("Object for the camera children wants to move with (the body target).")]
  30. [NoSaveDuringPlay]
  31. [VcamTargetProperty]
  32. public Transform m_Follow = null;
  33. /// <summary>Specifies the LensSettings of this Virtual Camera.
  34. /// These settings will be transferred to the Unity camera when the vcam is live.</summary>
  35. [Tooltip("Specifies the lens properties of this Virtual Camera. This generally mirrors the "
  36. + "Unity Camera's lens settings, and will be used to drive the Unity camera when the vcam is active.")]
  37. [LensSettingsProperty]
  38. public LensSettings m_Lens = LensSettings.Default;
  39. /// <summary> Collection of parameters that influence how this virtual camera transitions from
  40. /// other virtual cameras </summary>
  41. public TransitionParams m_Transitions;
  42. /// <summary>API for the editor, to make the dragging of position handles behave better.</summary>
  43. public bool UserIsDragging { get; set; }
  44. /// <summary>Updates the child rig cache</summary>
  45. protected override void OnEnable()
  46. {
  47. base.OnEnable();
  48. InvalidateComponentCache();
  49. }
  50. void Reset()
  51. {
  52. DestroyComponents();
  53. }
  54. /// <summary>Validates the settings avter inspector edit</summary>
  55. protected override void OnValidate()
  56. {
  57. base.OnValidate();
  58. m_Lens.Validate();
  59. }
  60. /// <summary>The camera state, which will be a blend of the child rig states</summary>
  61. override public CameraState State { get { return m_State; } }
  62. /// <summary>The camera state, which will be a blend of the child rig states</summary>
  63. protected CameraState m_State = CameraState.Default;
  64. /// <summary>Get the current LookAt target. Returns parent's LookAt if parent
  65. /// is non-null and no specific LookAt defined for this camera</summary>
  66. override public Transform LookAt
  67. {
  68. get { return ResolveLookAt(m_LookAt); }
  69. set { m_LookAt = value; }
  70. }
  71. /// <summary>Get the current Follow target. Returns parent's Follow if parent
  72. /// is non-null and no specific Follow defined for this camera</summary>
  73. override public Transform Follow
  74. {
  75. get { return ResolveFollow(m_Follow); }
  76. set { m_Follow = value; }
  77. }
  78. /// <summary>This is called to notify the vcam that a target got warped,
  79. /// so that the vcam can update its internal state to make the camera
  80. /// also warp seamlessy.</summary>
  81. /// <param name="target">The object that was warped</param>
  82. /// <param name="positionDelta">The amount the target's position changed</param>
  83. public override void OnTargetObjectWarped(Transform target, Vector3 positionDelta)
  84. {
  85. if (target == Follow)
  86. {
  87. transform.position += positionDelta;
  88. m_State.RawPosition += positionDelta;
  89. }
  90. UpdateComponentCache();
  91. for (int i = 0; i < m_Components.Length; ++i)
  92. {
  93. if (m_Components[i] != null)
  94. m_Components[i].OnTargetObjectWarped(target, positionDelta);
  95. }
  96. base.OnTargetObjectWarped(target, positionDelta);
  97. }
  98. /// <summary>
  99. /// Force the virtual camera to assume a given position and orientation
  100. /// </summary>
  101. /// <param name="pos">Worldspace pposition to take</param>
  102. /// <param name="rot">Worldspace orientation to take</param>
  103. public override void ForceCameraPosition(Vector3 pos, Quaternion rot)
  104. {
  105. PreviousStateIsValid = false;
  106. transform.position = pos;
  107. transform.rotation = rot;
  108. m_State.RawPosition = pos;
  109. m_State.RawOrientation = rot;
  110. UpdateComponentCache();
  111. for (int i = 0; i < m_Components.Length; ++i)
  112. if (m_Components[i] != null)
  113. m_Components[i].ForceCameraPosition(pos, rot);
  114. base.ForceCameraPosition(pos, rot);
  115. }
  116. /// <summary>
  117. /// Query components and extensions for the maximum damping time.
  118. /// </summary>
  119. /// <returns>Highest damping setting in this vcam</returns>
  120. public override float GetMaxDampTime()
  121. {
  122. float maxDamp = base.GetMaxDampTime();
  123. UpdateComponentCache();
  124. for (int i = 0; i < m_Components.Length; ++i)
  125. if (m_Components[i] != null)
  126. maxDamp = Mathf.Max(maxDamp, m_Components[i].GetMaxDampTime());
  127. return maxDamp;
  128. }
  129. /// <summary>If we are transitioning from another FreeLook, grab the axis values from it.</summary>
  130. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  131. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  132. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  133. public override void OnTransitionFromCamera(
  134. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
  135. {
  136. base.OnTransitionFromCamera(fromCam, worldUp, deltaTime);
  137. InvokeOnTransitionInExtensions(fromCam, worldUp, deltaTime);
  138. bool forceUpdate = false;
  139. if (m_Transitions.m_InheritPosition && fromCam != null)
  140. {
  141. transform.position = fromCam.State.RawPosition;
  142. //transform.rotation = fromCam.State.RawOrientation;
  143. PreviousStateIsValid = false;
  144. forceUpdate = true;
  145. }
  146. UpdateComponentCache();
  147. for (int i = 0; i < m_Components.Length; ++i)
  148. {
  149. if (m_Components[i] != null
  150. && m_Components[i].OnTransitionFromCamera(
  151. fromCam, worldUp, deltaTime, ref m_Transitions))
  152. forceUpdate = true;
  153. }
  154. if (forceUpdate)
  155. {
  156. InternalUpdateCameraState(worldUp, deltaTime);
  157. InternalUpdateCameraState(worldUp, deltaTime);
  158. }
  159. else
  160. UpdateCameraState(worldUp, deltaTime);
  161. if (m_Transitions.m_OnCameraLive != null)
  162. m_Transitions.m_OnCameraLive.Invoke(this, fromCam);
  163. }
  164. /// <summary>Internal use only. Called by CinemachineCore at designated update time
  165. /// so the vcam can position itself and track its targets. All 3 child rigs are updated,
  166. /// and a blend calculated, depending on the value of the Y axis.</summary>
  167. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  168. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
  169. override public void InternalUpdateCameraState(Vector3 worldUp, float deltaTime)
  170. {
  171. FollowTargetAttachment = 1;
  172. LookAtTargetAttachment = 1;
  173. // Initialize the camera state, in case the game object got moved in the editor
  174. m_State = PullStateFromVirtualCamera(worldUp, ref m_Lens);
  175. // Do our stuff
  176. SetReferenceLookAtTargetInState(ref m_State);
  177. InvokeComponentPipeline(ref m_State, worldUp, deltaTime);
  178. ApplyPositionBlendMethod(ref m_State, m_Transitions.m_BlendHint);
  179. // Push the raw position back to the game object's transform, so it
  180. // moves along with the camera.
  181. if (!UserIsDragging)
  182. {
  183. if (Follow != null)
  184. transform.position = State.RawPosition;
  185. if (LookAt != null)
  186. transform.rotation = State.RawOrientation;
  187. }
  188. // Signal that it's all done
  189. InvokePostPipelineStageCallback(this, CinemachineCore.Stage.Finalize, ref m_State, deltaTime);
  190. PreviousStateIsValid = true;
  191. }
  192. private Transform mCachedLookAtTarget;
  193. private CinemachineVirtualCameraBase mCachedLookAtTargetVcam;
  194. /// <summary>Set the state's refeenceLookAt target to our lookAt, with some smarts
  195. /// in case our LookAt points to a vcam</summary>
  196. protected void SetReferenceLookAtTargetInState(ref CameraState state)
  197. {
  198. Transform lookAtTarget = LookAt;
  199. if (lookAtTarget != mCachedLookAtTarget)
  200. {
  201. mCachedLookAtTarget = lookAtTarget;
  202. mCachedLookAtTargetVcam = null;
  203. if (lookAtTarget != null)
  204. mCachedLookAtTargetVcam = lookAtTarget.GetComponent<CinemachineVirtualCameraBase>();
  205. }
  206. if (lookAtTarget != null)
  207. {
  208. if (mCachedLookAtTargetVcam != null)
  209. state.ReferenceLookAt = mCachedLookAtTargetVcam.State.FinalPosition;
  210. else
  211. state.ReferenceLookAt = TargetPositionCache.GetTargetPosition(lookAtTarget);
  212. }
  213. }
  214. protected CameraState InvokeComponentPipeline(
  215. ref CameraState state, Vector3 worldUp, float deltaTime)
  216. {
  217. UpdateComponentCache();
  218. // Extensions first
  219. InvokePrePipelineMutateCameraStateCallback(this, ref state, deltaTime);
  220. // Apply the component pipeline
  221. for (CinemachineCore.Stage stage = CinemachineCore.Stage.Body;
  222. stage <= CinemachineCore.Stage.Finalize; ++stage)
  223. {
  224. var c = m_Components[(int)stage];
  225. if (c != null)
  226. c.PrePipelineMutateCameraState(ref state, deltaTime);
  227. }
  228. CinemachineComponentBase postAimBody = null;
  229. for (CinemachineCore.Stage stage = CinemachineCore.Stage.Body;
  230. stage <= CinemachineCore.Stage.Finalize; ++stage)
  231. {
  232. var c = m_Components[(int)stage];
  233. if (c != null)
  234. {
  235. if (stage == CinemachineCore.Stage.Body && c.BodyAppliesAfterAim)
  236. {
  237. postAimBody = c;
  238. continue; // do the body stage of the pipeline after Aim
  239. }
  240. c.MutateCameraState(ref state, deltaTime);
  241. }
  242. InvokePostPipelineStageCallback(this, stage, ref state, deltaTime);
  243. if (stage == CinemachineCore.Stage.Aim)
  244. {
  245. if (c == null)
  246. state.BlendHint |= CameraState.BlendHintValue.IgnoreLookAtTarget; // no aim
  247. // If we have saved a Body for after Aim, do it now
  248. if (postAimBody != null)
  249. {
  250. postAimBody.MutateCameraState(ref state, deltaTime);
  251. InvokePostPipelineStageCallback(this, CinemachineCore.Stage.Body, ref state, deltaTime);
  252. }
  253. }
  254. }
  255. return state;
  256. }
  257. // Component Cache - serialized only for copy/paste
  258. [SerializeField, HideInInspector, NoSaveDuringPlay]
  259. CinemachineComponentBase[] m_Components;
  260. /// For inspector
  261. internal CinemachineComponentBase[] ComponentCache
  262. {
  263. get
  264. {
  265. UpdateComponentCache();
  266. return m_Components;
  267. }
  268. }
  269. /// <summary>Call this when CinemachineCompponentBase compponents are added
  270. /// or removed. If you don't call this, you may get null reference errors.</summary>
  271. public void InvalidateComponentCache()
  272. {
  273. m_Components = null;
  274. }
  275. /// <summary>Bring the component cache up to date if needed</summary>
  276. protected void UpdateComponentCache()
  277. {
  278. #if UNITY_EDITOR
  279. // Special case: if we have serialized in with some other game object's
  280. // components, then we have just been pasted so we should clone them
  281. for (int i = 0; m_Components != null && i < m_Components.Length; ++i)
  282. {
  283. if (m_Components[i] != null && m_Components[i].gameObject != gameObject)
  284. {
  285. var copyFrom = m_Components;
  286. DestroyComponents();
  287. CopyComponents(copyFrom);
  288. break;
  289. }
  290. }
  291. #endif
  292. if (m_Components != null && m_Components.Length == (int)CinemachineCore.Stage.Finalize + 1)
  293. return; // up to date
  294. m_Components = new CinemachineComponentBase[(int)CinemachineCore.Stage.Finalize + 1];
  295. var existing = GetComponents<CinemachineComponentBase>();
  296. for (int i = 0; existing != null && i < existing.Length; ++i)
  297. m_Components[(int)existing[i].Stage] = existing[i];
  298. for (int i = 0; i < m_Components.Length; ++i)
  299. {
  300. if (m_Components[i] != null)
  301. {
  302. if (CinemachineCore.sShowHiddenObjects)
  303. m_Components[i].hideFlags &= ~HideFlags.HideInInspector;
  304. else
  305. m_Components[i].hideFlags |= HideFlags.HideInInspector;
  306. }
  307. }
  308. OnComponentCacheUpdated();
  309. }
  310. /// <summary>Notification that the component cache has just been update,
  311. /// in case a subclass needs to do something extra</summary>
  312. protected virtual void OnComponentCacheUpdated() {}
  313. /// <summary>Destroy all the CinmachineComponentBase components</summary>
  314. protected void DestroyComponents()
  315. {
  316. var existing = GetComponents<CinemachineComponentBase>();
  317. for (int i = 0; i < existing.Length; ++i)
  318. {
  319. #if UNITY_EDITOR
  320. UnityEditor.Undo.DestroyObjectImmediate(existing[i]);
  321. #else
  322. UnityEngine.Object.Destroy(existing[i]);
  323. #endif
  324. }
  325. InvalidateComponentCache();
  326. }
  327. #if UNITY_EDITOR
  328. // This gets called when user pastes component values
  329. void CopyComponents(CinemachineComponentBase[] copyFrom)
  330. {
  331. foreach (CinemachineComponentBase c in copyFrom)
  332. {
  333. if (c != null)
  334. {
  335. Type type = c.GetType();
  336. var copy = UnityEditor.Undo.AddComponent(gameObject, type);
  337. UnityEditor.Undo.RecordObject(copy, "copying pipeline");
  338. System.Reflection.BindingFlags bindingAttr
  339. = System.Reflection.BindingFlags.Public
  340. | System.Reflection.BindingFlags.NonPublic
  341. | System.Reflection.BindingFlags.Instance;
  342. System.Reflection.FieldInfo[] fields = type.GetFields(bindingAttr);
  343. for (int i = 0; i < fields.Length; ++i)
  344. if (!fields[i].IsStatic)
  345. fields[i].SetValue(copy, fields[i].GetValue(c));
  346. }
  347. }
  348. }
  349. #endif
  350. /// Legacy support for an old API. GML todo: deprecate these methods
  351. /// <summary>Get the component set for a specific stage.</summary>
  352. /// <param name="stage">The stage for which we want the component</param>
  353. /// <returns>The Cinemachine component for that stage, or null if not defined</returns>
  354. public CinemachineComponentBase GetCinemachineComponent(CinemachineCore.Stage stage)
  355. {
  356. var cache = ComponentCache;
  357. var i = (int)stage;
  358. return i >= 0 && i < cache.Length ? cache[i] : null;
  359. }
  360. /// <summary>Get an existing component of a specific type from the cinemachine pipeline.</summary>
  361. public T GetCinemachineComponent<T>() where T : CinemachineComponentBase
  362. {
  363. var components = ComponentCache;
  364. foreach (var c in components)
  365. if (c is T)
  366. return c as T;
  367. return null;
  368. }
  369. /// <summary>Add a component to the cinemachine pipeline.</summary>
  370. public T AddCinemachineComponent<T>() where T : CinemachineComponentBase
  371. {
  372. var components = ComponentCache;
  373. T c = gameObject.AddComponent<T>();
  374. var oldC = components[(int)c.Stage];
  375. if (oldC != null)
  376. {
  377. oldC.enabled = false;
  378. RuntimeUtility.DestroyObject(oldC);
  379. }
  380. InvalidateComponentCache();
  381. return c;
  382. }
  383. /// <summary>Remove a component from the cinemachine pipeline.</summary>
  384. public void DestroyCinemachineComponent<T>() where T : CinemachineComponentBase
  385. {
  386. var components = ComponentCache;
  387. foreach (var c in components)
  388. {
  389. if (c is T)
  390. {
  391. c.enabled = false;
  392. RuntimeUtility.DestroyObject(c);
  393. InvalidateComponentCache();
  394. return;
  395. }
  396. }
  397. }
  398. }
  399. }
  400. #endif