using System; using UnityEngine; namespace Cinemachine { /// /// Describes a blend between 2 Cinemachine Virtual Cameras, and holds the /// current state of the blend. /// public class CinemachineBlend { /// First camera in the blend public ICinemachineCamera CamA { get; set; } /// Second camera in the blend public ICinemachineCamera CamB { get; set; } /// The curve that describes the way the blend transitions over time /// from the first camera to the second. X-axis is time in seconds over which /// the blend takes place and Y axis is blend weight (0..1) public AnimationCurve BlendCurve { get; set; } /// The current time relative to the start of the blend public float TimeInBlend { get; set; } /// 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. public float BlendWeight { get { return BlendCurve != null ? BlendCurve.Evaluate(TimeInBlend) : 0; } } /// Validity test for the blend. True if both cameras are defined. public bool IsValid { get { return (CamA != null || CamB != null); } } /// Duration in seconds of the blend. /// This is given read from the BlendCurve. public float Duration { get; set; } /// True if the time relative to the start of the blend is greater /// than or equal to the blend duration public bool IsComplete { get { return TimeInBlend >= Duration; } } /// Text description of the blend, for debugging public string Description { get { string fromName = (CamA != null) ? "[" + CamA.Name + "]": "(none)"; string toName = (CamB != null) ? "[" + CamB.Name + "]" : "(none)"; int percent = (int)(BlendWeight * 100f); return string.Format("{0} {1}% from {2}", toName, percent, fromName); } } /// Does the blend use a specific Cinemachine Virtual Camera? /// The camera to test /// True if the camera is involved in the blend 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; } /// Construct a blend /// First camera /// Second camera /// Blend curve /// Current time in blend, relative to the start of the blend public CinemachineBlend( ICinemachineCamera a, ICinemachineCamera b, AnimationCurve curve, float duration, float t) { if (a == null || b == null) throw new ArgumentException("Blend cameras cannot be null"); CamA = a; CamB = b; BlendCurve = curve; TimeInBlend = t; Duration = duration; } /// Make sure the source cameras get updated. /// Default world up. Individual vcams may modify this /// Time increment used for calculating time-based behaviours (e.g. damping) 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) CinemachineCore.Instance.UpdateVirtualCamera(CamA, worldUp, deltaTime); CinemachineCore.Instance.UpdateVirtualCamera(CamB, worldUp, deltaTime); } /// Compute the blended CameraState for the current time in the blend. public CameraState State { get { return CameraState.Lerp(CamA.State, CamB.State, BlendWeight); } } } /// Definition of a Camera blend. This struct holds the information /// necessary to generate a suitable AnimationCurve for a Cinemachine Blend. [Serializable] [DocumentationSorting(10.2f, DocumentationSortingAttribute.Level.UserRef)] public struct CinemachineBlendDefinition { /// Supported predefined shapes for the blend curve. [DocumentationSorting(10.21f, DocumentationSortingAttribute.Level.UserRef)] public enum Style { /// Zero-length blend Cut, /// S-shaped curve, giving a gentle and smooth transition EaseInOut, /// Linear out of the outgoing shot, and easy into the incoming EaseIn, /// Easy out of the outgoing shot, and linear into the incoming EaseOut, /// Easy out of the outgoing, and hard into the incoming HardIn, /// Hard out of the outgoing, and easy into the incoming HardOut, /// Linear blend. Mechanical-looking. Linear }; /// The shape of the blend curve. [Tooltip("Shape of the blend curve")] public Style m_Style; /// The duration (in seconds) of the blend [Tooltip("Duration of the blend, in seconds")] public float m_Time; /// Constructor /// The shape of the blend curve. /// The duration (in seconds) of the blend public CinemachineBlendDefinition(Style style, float time) { m_Style = style; m_Time = time; } /// /// An AnimationCurve specifying the interpolation duration and value /// for this camera blend. The time of the last key frame is assumed to the be the /// duration of the blend. Y-axis values must be in range [0,1] (internally clamped /// within Blender) and time must be in range of [0, +infinity) /// public AnimationCurve BlendCurve { get { float time = Mathf.Max(0, m_Time); switch (m_Style) { default: case Style.Cut: return new AnimationCurve(); case Style.EaseInOut: return AnimationCurve.EaseInOut(0f, 0f, time, 1f); case Style.EaseIn: { AnimationCurve curve = AnimationCurve.Linear(0f, 0f, time, 1f); Keyframe[] keys = curve.keys; keys[1].inTangent = 0; curve.keys = keys; return curve; } case Style.EaseOut: { AnimationCurve curve = AnimationCurve.Linear(0f, 0f, time, 1f); Keyframe[] keys = curve.keys; keys[0].outTangent = 0; curve.keys = keys; return curve; } case Style.HardIn: { AnimationCurve curve = AnimationCurve.Linear(0f, 0f, time, 1f); Keyframe[] keys = curve.keys; keys[0].outTangent = 0; keys[1].inTangent = 1.5708f; // pi/2 = up curve.keys = keys; return curve; } case Style.HardOut: { AnimationCurve curve = AnimationCurve.Linear(0f, 0f, time, 1f); Keyframe[] keys = curve.keys; keys[0].outTangent = 1.5708f; // pi/2 = up keys[1].inTangent = 0; curve.keys = keys; return curve; } case Style.Linear: return AnimationCurve.Linear(0f, 0f, time, 1f); } } } } }