CinemachinePOV.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using Cinemachine.Utility;
  2. using UnityEngine;
  3. namespace Cinemachine
  4. {
  5. /// <summary>
  6. /// This is a CinemachineComponent in the Aim section of the component pipeline.
  7. /// Its job is to aim the camera in response to the user's mouse or joystick input.
  8. ///
  9. /// The composer does not change the camera's position. It will only pan and tilt the
  10. /// camera where it is, in order to get the desired framing. To move the camera, you have
  11. /// to use the virtual camera's Body section.
  12. /// </summary>
  13. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  14. [AddComponentMenu("")] // Don't display in add component menu
  15. [SaveDuringPlay]
  16. public class CinemachinePOV : CinemachineComponentBase
  17. {
  18. /// <summary>
  19. /// Defines the recentering target: Recentering goes here
  20. /// </summary>
  21. public enum RecenterTargetMode
  22. {
  23. /// <summary>
  24. /// Just go to 0
  25. /// </summary>
  26. None,
  27. /// <summary>
  28. /// Axis angles are relative to Follow target's forward
  29. /// </summary>
  30. FollowTargetForward,
  31. /// <summary>
  32. /// Axis angles are relative to LookAt target's forward
  33. /// </summary>
  34. LookAtTargetForward
  35. }
  36. /// <summary>
  37. /// Defines the recentering target: recentering goes here
  38. /// </summary>
  39. public RecenterTargetMode m_RecenterTarget = RecenterTargetMode.None;
  40. /// <summary>The Vertical axis. Value is -90..90. Controls the vertical orientation</summary>
  41. [Tooltip("The Vertical axis. Value is -90..90. Controls the vertical orientation")]
  42. [AxisStateProperty]
  43. public AxisState m_VerticalAxis = new AxisState(-70, 70, false, false, 300f, 0.1f, 0.1f, "Mouse Y", true);
  44. /// <summary>Controls how automatic recentering of the Vertical axis is accomplished</summary>
  45. [Tooltip("Controls how automatic recentering of the Vertical axis is accomplished")]
  46. public AxisState.Recentering m_VerticalRecentering = new AxisState.Recentering(false, 1, 2);
  47. /// <summary>The Horizontal axis. Value is -180..180. Controls the horizontal orientation</summary>
  48. [Tooltip("The Horizontal axis. Value is -180..180. Controls the horizontal orientation")]
  49. [AxisStateProperty]
  50. public AxisState m_HorizontalAxis = new AxisState(-180, 180, true, false, 300f, 0.1f, 0.1f, "Mouse X", false);
  51. /// <summary>Controls how automatic recentering of the Horizontal axis is accomplished</summary>
  52. [Tooltip("Controls how automatic recentering of the Horizontal axis is accomplished")]
  53. public AxisState.Recentering m_HorizontalRecentering = new AxisState.Recentering(false, 1, 2);
  54. /// <summary>Obsolete - no longer used</summary>
  55. [HideInInspector]
  56. [Tooltip("Obsolete - no longer used")]
  57. public bool m_ApplyBeforeBody;
  58. Quaternion m_PreviousCameraRotation;
  59. /// <summary>True if component is enabled and has a LookAt defined</summary>
  60. public override bool IsValid { get { return enabled; } }
  61. /// <summary>Get the Cinemachine Pipeline stage that this component implements.
  62. /// Always returns the Aim stage</summary>
  63. public override CinemachineCore.Stage Stage { get { return CinemachineCore.Stage.Aim; } }
  64. private void OnValidate()
  65. {
  66. m_VerticalAxis.Validate();
  67. m_VerticalRecentering.Validate();
  68. m_HorizontalAxis.Validate();
  69. m_HorizontalRecentering.Validate();
  70. }
  71. private void OnEnable()
  72. {
  73. UpdateInputAxisProvider();
  74. }
  75. /// <summary>
  76. /// API for the inspector. Internal use only
  77. /// </summary>
  78. public void UpdateInputAxisProvider()
  79. {
  80. m_HorizontalAxis.SetInputAxisProvider(0, null);
  81. m_VerticalAxis.SetInputAxisProvider(1, null);
  82. if (VirtualCamera != null)
  83. {
  84. var provider = VirtualCamera.GetInputAxisProvider();
  85. if (provider != null)
  86. {
  87. m_HorizontalAxis.SetInputAxisProvider(0, provider);
  88. m_VerticalAxis.SetInputAxisProvider(1, provider);
  89. }
  90. }
  91. }
  92. /// <summary>Does nothing</summary>
  93. /// <param name="state"></param>
  94. /// <param name="deltaTime"></param>
  95. public override void PrePipelineMutateCameraState(ref CameraState state, float deltaTime) {}
  96. /// <summary>Applies the axis values and orients the camera accordingly</summary>
  97. /// <param name="curState">The current camera state</param>
  98. /// <param name="deltaTime">Used for calculating damping. Not used.</param>
  99. public override void MutateCameraState(ref CameraState curState, float deltaTime)
  100. {
  101. if (!IsValid)
  102. return;
  103. // Only read joystick when game is playing
  104. if (deltaTime >= 0 && (!VirtualCamera.PreviousStateIsValid || !CinemachineCore.Instance.IsLive(VirtualCamera)))
  105. deltaTime = -1;
  106. if (deltaTime >= 0)
  107. {
  108. if (m_HorizontalAxis.Update(deltaTime))
  109. m_HorizontalRecentering.CancelRecentering();
  110. if (m_VerticalAxis.Update(deltaTime))
  111. m_VerticalRecentering.CancelRecentering();
  112. }
  113. var recenterTarget = GetRecenterTarget();
  114. m_HorizontalRecentering.DoRecentering(ref m_HorizontalAxis, deltaTime, recenterTarget.x);
  115. m_VerticalRecentering.DoRecentering(ref m_VerticalAxis, deltaTime, recenterTarget.y);
  116. // If we have a transform parent, then apply POV in the local space of the parent
  117. Quaternion rot = Quaternion.Euler(m_VerticalAxis.Value, m_HorizontalAxis.Value, 0);
  118. Transform parent = VirtualCamera.transform.parent;
  119. if (parent != null)
  120. rot = parent.rotation * rot;
  121. else
  122. rot = Quaternion.FromToRotation(Vector3.up, curState.ReferenceUp) * rot;
  123. curState.RawOrientation = rot;
  124. if (VirtualCamera.PreviousStateIsValid)
  125. curState.PositionDampingBypass = UnityVectorExtensions.SafeFromToRotation(
  126. m_PreviousCameraRotation * Vector3.forward,
  127. rot * Vector3.forward, curState.ReferenceUp).eulerAngles;
  128. m_PreviousCameraRotation = rot;
  129. }
  130. /// <summary>
  131. /// Get the horizonmtal and vertical angles that correspong to "at rest" position.
  132. /// </summary>
  133. /// <returns>X is horizontal angle (rot Y) and Y is vertical angle (rot X)</returns>
  134. public Vector2 GetRecenterTarget()
  135. {
  136. Transform t = null;
  137. switch (m_RecenterTarget)
  138. {
  139. case RecenterTargetMode.FollowTargetForward: t = VirtualCamera.Follow; break;
  140. case RecenterTargetMode.LookAtTargetForward: t = VirtualCamera.LookAt; break;
  141. default: break;
  142. }
  143. if (t != null)
  144. {
  145. var fwd = t.forward;
  146. Transform parent = VirtualCamera.transform.parent;
  147. if (parent != null)
  148. fwd = parent.rotation * fwd;
  149. var v = Quaternion.FromToRotation(Vector3.forward, fwd).eulerAngles;
  150. return new Vector2(NormalizeAngle(v.y), NormalizeAngle(v.x));
  151. }
  152. return Vector2.zero;
  153. }
  154. // Normalize angle value to [-180, 180] degrees.
  155. static float NormalizeAngle(float angle)
  156. {
  157. return ((angle + 180) % 360) - 180;
  158. }
  159. /// <summary>
  160. /// Force the virtual camera to assume a given position and orientation.
  161. /// Procedural placement then takes over
  162. /// </summary>
  163. /// <param name="pos">Worldspace pposition to take</param>
  164. /// <param name="rot">Worldspace orientation to take</param>
  165. public override void ForceCameraPosition(Vector3 pos, Quaternion rot)
  166. {
  167. SetAxesForRotation(rot);
  168. }
  169. /// <summary>Notification that this virtual camera is going live.
  170. /// Base class implementation does nothing.</summary>
  171. /// <param name="fromCam">The camera being deactivated. May be null.</param>
  172. /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
  173. /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
  174. /// <param name="transitionParams">Transition settings for this vcam</param>
  175. /// <returns>True if the vcam should do an internal update as a result of this call</returns>
  176. public override bool OnTransitionFromCamera(
  177. ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime,
  178. ref CinemachineVirtualCameraBase.TransitionParams transitionParams)
  179. {
  180. m_HorizontalRecentering.DoRecentering(ref m_HorizontalAxis, -1, 0);
  181. m_VerticalRecentering.DoRecentering(ref m_VerticalAxis, -1, 0);
  182. m_HorizontalRecentering.CancelRecentering();
  183. m_VerticalRecentering.CancelRecentering();
  184. if (fromCam != null && transitionParams.m_InheritPosition
  185. && !CinemachineCore.Instance.IsLiveInBlend(VirtualCamera))
  186. {
  187. SetAxesForRotation(fromCam.State.RawOrientation);
  188. return true;
  189. }
  190. return false;
  191. }
  192. /// <summary>POV is controlled by input.</summary>
  193. public override bool RequiresUserInput => true;
  194. void SetAxesForRotation(Quaternion targetRot)
  195. {
  196. Vector3 up = VcamState.ReferenceUp;
  197. Vector3 fwd = Vector3.forward;
  198. Transform parent = VirtualCamera.transform.parent;
  199. if (parent != null)
  200. fwd = parent.rotation * fwd;
  201. m_HorizontalAxis.Value = 0;
  202. m_HorizontalAxis.Reset();
  203. Vector3 targetFwd = targetRot * Vector3.forward;
  204. Vector3 a = fwd.ProjectOntoPlane(up);
  205. Vector3 b = targetFwd.ProjectOntoPlane(up);
  206. if (!a.AlmostZero() && !b.AlmostZero())
  207. m_HorizontalAxis.Value = Vector3.SignedAngle(a, b, up);
  208. m_VerticalAxis.Value = 0;
  209. m_VerticalAxis.Reset();
  210. fwd = Quaternion.AngleAxis(m_HorizontalAxis.Value, up) * fwd;
  211. Vector3 right = Vector3.Cross(up, fwd);
  212. if (!right.AlmostZero())
  213. m_VerticalAxis.Value = Vector3.SignedAngle(fwd, targetFwd, right);
  214. }
  215. }
  216. }