| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- using Cinemachine.Utility;
- using System;
- using UnityEngine;
- namespace Cinemachine
- {
- /// <summary>
- /// Describes a blend between 2 Cinemachine Virtual Cameras, and holds the
- /// current state of the blend.
- /// </summary>
- public class CinemachineBlend
- {
- /// <summary>First camera in the blend</summary>
- public ICinemachineCamera CamA { get; set; }
- /// <summary>Second camera in the blend</summary>
- public ICinemachineCamera CamB { get; set; }
- /// <summary>The curve that describes the way the blend transitions over time
- /// from the first camera to the second. X-axis is normalized time (0...1) over which
- /// the blend takes place and Y axis is blend weight (0..1)</summary>
- public AnimationCurve BlendCurve { get; set; }
- /// <summary>The current time relative to the start of the blend</summary>
- public float TimeInBlend { get; set; }
- /// <summary>The current weight of the blend. This is an evaluation of the
- /// BlendCurve at the current time relative to the start of the blend.
- /// 0 means camA, 1 means camB.</summary>
- public float BlendWeight
- {
- get
- {
- if (BlendCurve == null || BlendCurve.length < 2 || IsComplete)
- return 1;
- return Mathf.Clamp01(BlendCurve.Evaluate(TimeInBlend / Duration));
- }
- }
- /// <summary>Validity test for the blend. True if either camera is defined.</summary>
- public bool IsValid { get { return ((CamA != null && CamA.IsValid) || (CamB != null && CamB.IsValid)); } }
- /// <summary>Duration in seconds of the blend.</summary>
- public float Duration { get; set; }
- /// <summary>True if the time relative to the start of the blend is greater
- /// than or equal to the blend duration</summary>
- public bool IsComplete { get { return TimeInBlend >= Duration || !IsValid; } }
- /// <summary>Text description of the blend, for debugging</summary>
- public string Description
- {
- get
- {
- var sb = CinemachineDebug.SBFromPool();
- if (CamB == null || !CamB.IsValid)
- sb.Append("(none)");
- else
- {
- sb.Append("[");
- sb.Append(CamB.Name);
- sb.Append("]");
- }
- sb.Append(" ");
- sb.Append((int)(BlendWeight * 100f));
- sb.Append("% from ");
- if (CamA == null || !CamA.IsValid)
- sb.Append("(none)");
- else
- {
- sb.Append("[");
- sb.Append(CamA.Name);
- sb.Append("]");
- }
- string text = sb.ToString();
- CinemachineDebug.ReturnToPool(sb);
- return text;
- }
- }
- /// <summary>Does the blend use a specific Cinemachine Virtual Camera?</summary>
- /// <param name="cam">The camera to test</param>
- /// <returns>True if the camera is involved in the blend</returns>
- public bool Uses(ICinemachineCamera cam)
- {
- if (cam == CamA || cam == CamB)
- return true;
- BlendSourceVirtualCamera b = CamA as BlendSourceVirtualCamera;
- if (b != null && b.Blend.Uses(cam))
- return true;
- b = CamB as BlendSourceVirtualCamera;
- if (b != null && b.Blend.Uses(cam))
- return true;
- return false;
- }
- /// <summary>Construct a blend</summary>
- /// <param name="a">First camera</param>
- /// <param name="b">Second camera</param>
- /// <param name="curve">Blend curve</param>
- /// <param name="duration">Duration of the blend, in seconds</param>
- /// <param name="t">Current time in blend, relative to the start of the blend</param>
- public CinemachineBlend(
- ICinemachineCamera a, ICinemachineCamera b, AnimationCurve curve, float duration, float t)
- {
- CamA = a;
- CamB = b;
- BlendCurve = curve;
- TimeInBlend = t;
- Duration = duration;
- }
- /// <summary>Make sure the source cameras get updated.</summary>
- /// <param name="worldUp">Default world up. Individual vcams may modify this</param>
- /// <param name="deltaTime">Time increment used for calculating time-based behaviours (e.g. damping)</param>
- public void UpdateCameraState(Vector3 worldUp, float deltaTime)
- {
- // Make sure both cameras have been updated (they are not necessarily
- // enabled, and only enabled cameras get updated automatically
- // every frame)
- if (CamA != null && CamA.IsValid)
- CamA.UpdateCameraState(worldUp, deltaTime);
- if (CamB != null && CamB.IsValid)
- CamB.UpdateCameraState(worldUp, deltaTime);
- }
- /// <summary>Compute the blended CameraState for the current time in the blend.</summary>
- public CameraState State
- {
- get
- {
- if (CamA == null || !CamA.IsValid)
- {
- if (CamB == null || !CamB.IsValid)
- return CameraState.Default;
- return CamB.State;
- }
- if (CamB == null || !CamB.IsValid)
- return CamA.State;
- return CameraState.Lerp(CamA.State, CamB.State, BlendWeight);
- }
- }
- }
- /// <summary>Definition of a Camera blend. This struct holds the information
- /// necessary to generate a suitable AnimationCurve for a Cinemachine Blend.</summary>
- [Serializable]
- [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
- public struct CinemachineBlendDefinition
- {
- /// <summary>Supported predefined shapes for the blend curve.</summary>
- [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
- public enum Style
- {
- /// <summary>Zero-length blend</summary>
- Cut,
- /// <summary>S-shaped curve, giving a gentle and smooth transition</summary>
- EaseInOut,
- /// <summary>Linear out of the outgoing shot, and easy into the incoming</summary>
- EaseIn,
- /// <summary>Easy out of the outgoing shot, and linear into the incoming</summary>
- EaseOut,
- /// <summary>Easy out of the outgoing, and hard into the incoming</summary>
- HardIn,
- /// <summary>Hard out of the outgoing, and easy into the incoming</summary>
- HardOut,
- /// <summary>Linear blend. Mechanical-looking.</summary>
- Linear,
- /// <summary>Custom blend curve.</summary>
- Custom
- };
- /// <summary>The shape of the blend curve.</summary>
- [Tooltip("Shape of the blend curve")]
- public Style m_Style;
- /// <summary>The duration (in seconds) of the blend, if not a cut.
- /// If style is a cut, then this value is ignored.</summary>
- [Tooltip("Duration of the blend, in seconds")]
- public float m_Time;
- /// <summary>
- /// Get the duration of the blend, in seconds. Will return 0 if blend style is a cut.
- /// </summary>
- public float BlendTime { get { return m_Style == Style.Cut ? 0 : m_Time; } }
- /// <summary>Constructor</summary>
- /// <param name="style">The shape of the blend curve.</param>
- /// <param name="time">The duration (in seconds) of the blend</param>
- public CinemachineBlendDefinition(Style style, float time)
- {
- m_Style = style;
- m_Time = time;
- m_CustomCurve = null;
- }
- /// <summary>
- /// A user-defined AnimationCurve, used only if style is Custom.
- /// Curve MUST be normalized, i.e. time range [0...1], value range [0...1].
- /// </summary>
- public AnimationCurve m_CustomCurve;
- static AnimationCurve[] sStandardCurves;
- void CreateStandardCurves()
- {
- sStandardCurves = new AnimationCurve[(int)Style.Custom];
- sStandardCurves[(int)Style.Cut] = null;
- sStandardCurves[(int)Style.EaseInOut] = AnimationCurve.EaseInOut(0f, 0f, 1, 1f);
- sStandardCurves[(int)Style.EaseIn] = AnimationCurve.Linear(0f, 0f, 1, 1f);
- Keyframe[] keys = sStandardCurves[(int)Style.EaseIn].keys;
- keys[0].outTangent = 1.4f;
- keys[1].inTangent = 0;
- sStandardCurves[(int)Style.EaseIn].keys = keys;
- sStandardCurves[(int)Style.EaseOut] = AnimationCurve.Linear(0f, 0f, 1, 1f);
- keys = sStandardCurves[(int)Style.EaseOut].keys;
- keys[0].outTangent = 0;
- keys[1].inTangent = 1.4f;
- sStandardCurves[(int)Style.EaseOut].keys = keys;
- sStandardCurves[(int)Style.HardIn] = AnimationCurve.Linear(0f, 0f, 1, 1f);
- keys = sStandardCurves[(int)Style.HardIn].keys;
- keys[0].outTangent = 0;
- keys[1].inTangent = 3f;
- sStandardCurves[(int)Style.HardIn].keys = keys;
- sStandardCurves[(int)Style.HardOut] = AnimationCurve.Linear(0f, 0f, 1, 1f);
- keys = sStandardCurves[(int)Style.HardOut].keys;
- keys[0].outTangent = 3f;
- keys[1].inTangent = 0;
- sStandardCurves[(int)Style.HardOut].keys = keys;
- sStandardCurves[(int)Style.Linear] = AnimationCurve.Linear(0f, 0f, 1, 1f);
- }
- /// <summary>
- /// A normalized AnimationCurve specifying the interpolation curve
- /// for this camera blend. Y-axis values must be in range [0,1] (internally clamped
- /// within Blender) and time must be in range of [0, 1].
- /// </summary>
- public AnimationCurve BlendCurve
- {
- get
- {
- if (m_Style == Style.Custom)
- {
- if (m_CustomCurve == null)
- m_CustomCurve = AnimationCurve.EaseInOut(0f, 0f, 1, 1f);
- return m_CustomCurve;
- }
- if (sStandardCurves == null)
- CreateStandardCurves();
- return sStandardCurves[(int)m_Style];
- }
- }
- }
- /// <summary>
- /// Point source for blending. It's not really a virtual camera, but takes
- /// a CameraState and exposes it as a virtual camera for the purposes of blending.
- /// </summary>
- internal class StaticPointVirtualCamera : ICinemachineCamera
- {
- public StaticPointVirtualCamera(CameraState state, string name) { State = state; Name = name; }
- public void SetState(CameraState state) { State = state; }
- public string Name { get; private set; }
- public string Description { get { return ""; }}
- public int Priority { get; set; }
- public Transform LookAt { get; set; }
- public Transform Follow { get; set; }
- public CameraState State { get; private set; }
- public GameObject VirtualCameraGameObject { get { return null; } }
- public bool IsValid { get { return true; } }
- public ICinemachineCamera ParentCamera { get { return null; } }
- public bool IsLiveChild(ICinemachineCamera vcam, bool dominantChildOnly = false) { return false; }
- public void UpdateCameraState(Vector3 worldUp, float deltaTime) {}
- public void InternalUpdateCameraState(Vector3 worldUp, float deltaTime) {}
- public void OnTransitionFromCamera(ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime) {}
- public void OnTargetObjectWarped(Transform target, Vector3 positionDelta) {}
- }
- /// <summary>
- /// Blend result source for blending. This exposes a CinemachineBlend object
- /// as an ersatz virtual camera for the purposes of blending. This achieves the purpose
- /// of blending the result oif a blend.
- /// </summary>
- internal class BlendSourceVirtualCamera : ICinemachineCamera
- {
- public BlendSourceVirtualCamera(CinemachineBlend blend) { Blend = blend; }
- public CinemachineBlend Blend { get; set; }
- public string Name { get { return "Mid-blend"; }}
- public string Description { get { return Blend == null ? "(null)" : Blend.Description; }}
- public int Priority { get; set; }
- public Transform LookAt { get; set; }
- public Transform Follow { get; set; }
- public CameraState State { get; private set; }
- public GameObject VirtualCameraGameObject { get { return null; } }
- public bool IsValid { get { return Blend != null && Blend.IsValid; } }
- public ICinemachineCamera ParentCamera { get { return null; } }
- public bool IsLiveChild(ICinemachineCamera vcam, bool dominantChildOnly = false)
- { return Blend != null && (vcam == Blend.CamA || vcam == Blend.CamB); }
- public CameraState CalculateNewState(float deltaTime) { return State; }
- public void UpdateCameraState(Vector3 worldUp, float deltaTime)
- {
- if (Blend != null)
- {
- Blend.UpdateCameraState(worldUp, deltaTime);
- State = Blend.State;
- }
- }
- public void InternalUpdateCameraState(Vector3 worldUp, float deltaTime) {}
- public void OnTransitionFromCamera(ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime) {}
- public void OnTargetObjectWarped(Transform target, Vector3 positionDelta) {}
- }
- }
|