CinemachineFollowZoom.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using UnityEngine;
  2. using Cinemachine.Utility;
  3. namespace Cinemachine
  4. {
  5. /// <summary>
  6. /// An add-on module for Cinemachine Virtual Camera that adjusts
  7. /// the FOV of the lens to keep the target object at a constant size on the screen,
  8. /// regardless of camera and target position.
  9. /// </summary>
  10. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  11. [AddComponentMenu("")] // Hide in menu
  12. [SaveDuringPlay]
  13. #if UNITY_2018_3_OR_NEWER
  14. [ExecuteAlways]
  15. #else
  16. [ExecuteInEditMode]
  17. #endif
  18. [DisallowMultipleComponent]
  19. [HelpURL(Documentation.BaseURL + "manual/CinemachineFollowZoom.html")]
  20. public class CinemachineFollowZoom : CinemachineExtension
  21. {
  22. /// <summary>The shot width to maintain, in world units, at target distance.
  23. /// FOV will be adusted as far as possible to maintain this width at the
  24. /// target distance from the camera.</summary>
  25. [Tooltip("The shot width to maintain, in world units, at target distance.")]
  26. public float m_Width = 2f;
  27. /// <summary>Increase this value to soften the aggressiveness of the follow-zoom.
  28. /// Small numbers are more responsive, larger numbers give a more heavy slowly responding camera. </summary>
  29. [Range(0f, 20f)]
  30. [Tooltip("Increase this value to soften the aggressiveness of the follow-zoom. Small numbers are more responsive, larger numbers give a more heavy slowly responding camera.")]
  31. public float m_Damping = 1f;
  32. /// <summary>Will not generate an FOV smaller than this.</summary>
  33. [Range(1f, 179f)]
  34. [Tooltip("Lower limit for the FOV that this behaviour will generate.")]
  35. public float m_MinFOV = 3f;
  36. /// <summary>Will not generate an FOV larget than this.</summary>
  37. [Range(1f, 179f)]
  38. [Tooltip("Upper limit for the FOV that this behaviour will generate.")]
  39. public float m_MaxFOV = 60f;
  40. private void OnValidate()
  41. {
  42. m_Width = Mathf.Max(0, m_Width);
  43. m_MaxFOV = Mathf.Clamp(m_MaxFOV, 1, 179);
  44. m_MinFOV = Mathf.Clamp(m_MinFOV, 1, m_MaxFOV);
  45. }
  46. class VcamExtraState
  47. {
  48. public float m_previousFrameZoom = 0;
  49. }
  50. /// <summary>
  51. /// Report maximum damping time needed for this component.
  52. /// </summary>
  53. /// <returns>Highest damping setting in this component</returns>
  54. public override float GetMaxDampTime()
  55. {
  56. return m_Damping;
  57. }
  58. /// <summary>Callback to preform the zoom adjustment</summary>
  59. /// <param name="vcam">The virtual camera being processed</param>
  60. /// <param name="stage">The current pipeline stage</param>
  61. /// <param name="state">The current virtual camera state</param>
  62. /// <param name="deltaTime">The current applicable deltaTime</param>
  63. protected override void PostPipelineStageCallback(
  64. CinemachineVirtualCameraBase vcam,
  65. CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
  66. {
  67. VcamExtraState extra = GetExtraState<VcamExtraState>(vcam);
  68. if (deltaTime < 0 || !VirtualCamera.PreviousStateIsValid)
  69. extra.m_previousFrameZoom = state.Lens.FieldOfView;
  70. // Set the zoom after the body has been positioned, but before the aim,
  71. // so that composer can compose using the updated fov.
  72. if (stage == CinemachineCore.Stage.Body)
  73. {
  74. // Try to reproduce the target width
  75. float targetWidth = Mathf.Max(m_Width, 0);
  76. float fov = 179f;
  77. float d = Vector3.Distance(state.CorrectedPosition, state.ReferenceLookAt);
  78. if (d > UnityVectorExtensions.Epsilon)
  79. {
  80. // Clamp targetWidth to FOV min/max
  81. float minW = d * 2f * Mathf.Tan(m_MinFOV * Mathf.Deg2Rad / 2f);
  82. float maxW = d * 2f * Mathf.Tan(m_MaxFOV * Mathf.Deg2Rad / 2f);
  83. targetWidth = Mathf.Clamp(targetWidth, minW, maxW);
  84. // Apply damping
  85. if (deltaTime >= 0 && m_Damping > 0 && VirtualCamera.PreviousStateIsValid)
  86. {
  87. float currentWidth = d * 2f * Mathf.Tan(extra.m_previousFrameZoom * Mathf.Deg2Rad / 2f);
  88. float delta = targetWidth - currentWidth;
  89. delta = VirtualCamera.DetachedLookAtTargetDamp(delta, m_Damping, deltaTime);
  90. targetWidth = currentWidth + delta;
  91. }
  92. fov = 2f * Mathf.Atan(targetWidth / (2 * d)) * Mathf.Rad2Deg;
  93. }
  94. LensSettings lens = state.Lens;
  95. lens.FieldOfView = extra.m_previousFrameZoom = Mathf.Clamp(fov, m_MinFOV, m_MaxFOV);
  96. state.Lens = lens;
  97. }
  98. }
  99. }
  100. }