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);
}
}
}
}
}