| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726 |
- using System;
- using System.Collections.Generic;
- using Cinemachine.Utility;
- using UnityEngine;
- using UnityEngine.Serialization;
- namespace Cinemachine
- {
- /// <summary>
- /// Base class for a Monobehaviour that represents a Virtual Camera within the Unity scene.
- ///
- /// This is intended to be attached to an empty Transform GameObject.
- /// Inherited classes can be either standalone virtual cameras such
- /// as CinemachineVirtualCamera, or meta-cameras such as
- /// CinemachineClearShot or CinemachineFreeLook.
- ///
- /// A CinemachineVirtualCameraBase exposes a Priority property. When the behaviour is
- /// enabled in the game, the Virtual Camera is automatically placed in a queue
- /// maintained by the static CinemachineCore singleton.
- /// The queue is sorted by priority. When a Unity camera is equipped with a
- /// CinemachineBrain behaviour, the brain will choose the camera
- /// at the head of the queue. If you have multiple Unity cameras with CinemachineBrain
- /// behaviours (say in a split-screen context), then you can filter the queue by
- /// setting the culling flags on the virtual cameras. The culling mask of the
- /// Unity Camera will then act as a filter for the brain. Apart from this,
- /// there is nothing that prevents a virtual camera from controlling multiple
- /// Unity cameras simultaneously.
- /// </summary>
- [SaveDuringPlay]
- public abstract class CinemachineVirtualCameraBase : MonoBehaviour, ICinemachineCamera
- {
- /// <summary>Inspector control - Use for hiding sections of the Inspector UI.</summary>
- [HideInInspector, SerializeField, NoSaveDuringPlay]
- public string[] m_ExcludedPropertiesInInspector = new string[] { "m_Script" };
- /// <summary>Inspector control - Use for enabling sections of the Inspector UI.</summary>
- [HideInInspector, SerializeField, NoSaveDuringPlay]
- public CinemachineCore.Stage[] m_LockStageInInspector;
- /// <summary>Version that was last streamed, for upgrading legacy</summary>
- public int ValidatingStreamVersion
- {
- get { return m_OnValidateCalled ? m_ValidatingStreamVersion : CinemachineCore.kStreamingVersion; }
- private set { m_ValidatingStreamVersion = value; }
- }
- private int m_ValidatingStreamVersion = 0;
- private bool m_OnValidateCalled = false;
- [HideInInspector, SerializeField, NoSaveDuringPlay]
- private int m_StreamingVersion;
- /// <summary>The priority will determine which camera becomes active based on the
- /// state of other cameras and this camera. Higher numbers have greater priority.
- /// </summary>
- [NoSaveDuringPlay]
- [Tooltip("The priority will determine which camera becomes active based on the state of "
- + "other cameras and this camera. Higher numbers have greater priority.")]
- public int m_Priority = 10;
- /// <summary>
- /// This must be set every frame at the start of the pipeline to relax the virtual camera's
- /// attachment to the target. Range is 0...1.
- /// 1 is full attachment, and is the normal state.
- /// 0 is no attachment, and virtual camera will behave as if no Follow
- /// targets are set.
- /// </summary>
- public float FollowTargetAttachment { get; set; }
- /// <summary>
- /// This must be set every frame at the start of the pipeline to relax the virtual camera's
- /// attachment to the target. Range is 0...1.
- /// 1 is full attachment, and is the normal state.
- /// 0 is no attachment, and virtual camera will behave as if no LookAt
- /// targets are set.
- /// </summary>
- public float LookAtTargetAttachment { get; set; }
- /// <summary>
- /// How often to update a virtual camera when it is in Standby mode
- /// </summary>
- public enum StandbyUpdateMode
- {
- /// <summary>Only update if the virtual camera is Live</summary>
- Never,
- /// <summary>Update the virtual camera every frame, even when it is not Live</summary>
- Always,
- /// <summary>Update the virtual camera occasionally, the exact frequency depends
- /// on how many other virtual cameras are in Standby</summary>
- RoundRobin
- };
- /// <summary>When the virtual camera is not live, this is how often the virtual camera will
- /// be updated. Set this to tune for performance. Most of the time Never is fine, unless
- /// the virtual camera is doing shot evaluation.
- /// </summary>
- [Tooltip("When the virtual camera is not live, this is how often the virtual camera will be updated. "
- + "Set this to tune for performance. Most of the time Never is fine, "
- + "unless the virtual camera is doing shot evaluation.")]
- public StandbyUpdateMode m_StandbyUpdate = StandbyUpdateMode.RoundRobin;
- /// <summary>
- /// Query components and extensions for the maximum damping time.
- /// Base class implementation queries extensions.
- /// Only used in editor for timeline scrubbing.
- /// </summary>
- /// <returns>Highest damping setting in this vcam</returns>
- public virtual float GetMaxDampTime()
- {
- float maxDamp = 0;
- if (mExtensions != null)
- for (int i = 0; i < mExtensions.Count; ++i)
- maxDamp = Mathf.Max(maxDamp, mExtensions[i].GetMaxDampTime());
- return maxDamp;
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public float DetachedFollowTargetDamp(float initial, float dampTime, float deltaTime)
- {
- dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, FollowTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public Vector3 DetachedFollowTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
- {
- dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, FollowTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public Vector3 DetachedFollowTargetDamp(Vector3 initial, float dampTime, float deltaTime)
- {
- dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, FollowTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public float DetachedLookAtTargetDamp(float initial, float dampTime, float deltaTime)
- {
- dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, LookAtTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public Vector3 DetachedLookAtTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
- {
- dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, LookAtTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>Get a damped version of a quantity. This is the portion of the
- /// quantity that will take effect over the given time.
- /// This method takes the target attachment into account. For general
- /// damping without consideration of target attachment, use Damper.Damp()</summary>
- /// <param name="initial">The amount that will be damped</param>
- /// <param name="dampTime">The rate of damping. This is the time it would
- /// take to reduce the original amount to a negligible percentage</param>
- /// <param name="deltaTime">The time over which to damp</param>
- /// <returns>The damped amount. This will be the original amount scaled by
- /// a value between 0 and 1.</returns>
- public Vector3 DetachedLookAtTargetDamp(Vector3 initial, float dampTime, float deltaTime)
- {
- dampTime = Mathf.Lerp(Mathf.Max(1, dampTime), dampTime, LookAtTargetAttachment);
- deltaTime = Mathf.Lerp(0, deltaTime, LookAtTargetAttachment);
- return Damper.Damp(initial, dampTime, deltaTime);
- }
- /// <summary>
- /// A delegate to hook into the state calculation pipeline.
- /// This will be called after each pipeline stage, to allow others to hook into the pipeline.
- /// See CinemachineCore.Stage.
- /// </summary>
- /// <param name="extension">The extension to add.</param>
- public virtual void AddExtension(CinemachineExtension extension)
- {
- if (mExtensions == null)
- mExtensions = new List<CinemachineExtension>();
- else
- mExtensions.Remove(extension);
- mExtensions.Add(extension);
- }
- /// <summary>Remove a Pipeline stage hook callback.</summary>
- /// <param name="extension">The extension to remove.</param>
- public virtual void RemoveExtension(CinemachineExtension extension)
- {
- if (mExtensions != null)
- mExtensions.Remove(extension);
- }
- /// <summary> Tee extensions connected to this vcam</summary>
- List<CinemachineExtension> mExtensions;
- /// <summary>
- /// Invokes the PostPipelineStageDelegate for this camera, and up the hierarchy for all
- /// parent cameras (if any).
- /// Implementaion must be sure to call this after each pipeline stage, to allow
- /// other services to hook into the pipeline.
- /// See CinemachineCore.Stage.
- /// </summary>
- /// <param name="vcam">The virtual camera being processed</param>
- /// <param name="stage">The current pipeline stage</param>
- /// <param name="newState">The current virtual camera state</param>
- /// <param name="deltaTime">The current applicable deltaTime</param>
- protected void InvokePostPipelineStageCallback(
- CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage,
- ref CameraState newState, float deltaTime)
- {
- if (mExtensions != null)
- {
- for (int i = 0; i < mExtensions.Count; ++i)
- {
- var e = mExtensions[i];
- if (e == null)
- {
- // Object was deleted (possibly because of Undo in the editor)
- mExtensions.RemoveAt(i);
- --i;
- }
- else if (e.enabled)
- e.InvokePostPipelineStageCallback(vcam, stage, ref newState, deltaTime);
- }
- }
- CinemachineVirtualCameraBase parent = ParentCamera as CinemachineVirtualCameraBase;
- if (parent != null)
- parent.InvokePostPipelineStageCallback(vcam, stage, ref newState, deltaTime);
- }
-
- /// <summary>
- /// Invokes the PrePipelineMutateCameraStateCallback for this camera,
- /// and up the hierarchy for all parent cameras (if any).
- /// Implementaion must be sure to call this after each pipeline stage, to allow
- /// other services to hook into the pipeline.
- /// See CinemachineCore.Stage.
- /// </summary>
- /// <param name="vcam">The virtual camera being processed</param>
- /// <param name="newState">The current virtual camera state</param>
- /// <param name="deltaTime">The current applicable deltaTime</param>
- protected void InvokePrePipelineMutateCameraStateCallback(
- CinemachineVirtualCameraBase vcam, ref CameraState newState, float deltaTime)
- {
- if (mExtensions != null)
- {
- for (int i = 0; i < mExtensions.Count; ++i)
- {
- var e = mExtensions[i];
- if (e == null)
- {
- // Object was deleted (possibly because of Undo in the editor)
- mExtensions.RemoveAt(i);
- --i;
- }
- else if (e.enabled)
- e.PrePipelineMutateCameraStateCallback(vcam, ref newState, deltaTime);
- }
- }
- CinemachineVirtualCameraBase parent = ParentCamera as CinemachineVirtualCameraBase;
- if (parent != null)
- parent.InvokePrePipelineMutateCameraStateCallback(vcam, ref newState, deltaTime);
- }
- /// <summary>
- /// Invokes the OnTransitionFromCamera for all extensions on this camera
- /// </summary>
- /// <param name="fromCam">The camera being deactivated. May be null.</param>
- /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
- /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
- /// <returns>True to request a vcam update of internal state</returns>
- protected bool InvokeOnTransitionInExtensions(
- ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
- {
- bool forceUpdate = false;
- if (mExtensions != null)
- {
- for (int i = 0; i < mExtensions.Count; ++i)
- {
- var e = mExtensions[i];
- if (e == null)
- {
- // Object was deleted (possibly because of Undo in the editor)
- mExtensions.RemoveAt(i);
- --i;
- }
- else if (e.enabled && e.OnTransitionFromCamera(fromCam, worldUp, deltaTime))
- forceUpdate = true;
- }
- }
- return forceUpdate;
- }
- /// <summary>Get the name of the Virtual Camera. Base implementation
- /// returns the owner GameObject's name.</summary>
- public string Name { get { return name; } }
- /// <summary>Gets a brief debug description of this virtual camera, for use when displayiong debug info</summary>
- public virtual string Description { get { return ""; }}
- /// <summary>Get the Priority of the virtual camera. This determines its placement
- /// in the CinemachineCore's queue of eligible shots.</summary>
- public int Priority { get { return m_Priority; } set { m_Priority = value; } }
- /// <summary>Hint for blending to and from this virtual camera</summary>
- public enum BlendHint
- {
- /// <summary>Standard linear position and aim blend</summary>
- None,
- /// <summary>Spherical blend about LookAt target position if there is a LookAt target, linear blend between LookAt targets</summary>
- SphericalPosition,
- /// <summary>Cylindrical blend about LookAt target position if there is a LookAt target (vertical co-ordinate is linearly interpolated), linear blend between LookAt targets</summary>
- CylindricalPosition,
- /// <summary>Standard linear position blend, radial blend between LookAt targets</summary>
- ScreenSpaceAimWhenTargetsDiffer
- }
- /// <summary>Applies a position blend hint to the camera state</summary>
- protected void ApplyPositionBlendMethod(ref CameraState state, BlendHint hint)
- {
- switch (hint)
- {
- default:
- break;
- case BlendHint.SphericalPosition:
- state.BlendHint |= CameraState.BlendHintValue.SphericalPositionBlend;
- break;
- case BlendHint.CylindricalPosition:
- state.BlendHint |= CameraState.BlendHintValue.CylindricalPositionBlend;
- break;
- case BlendHint.ScreenSpaceAimWhenTargetsDiffer:
- state.BlendHint |= CameraState.BlendHintValue.RadialAimBlend;
- break;
- }
- }
- /// <summary>The GameObject owner of the Virtual Camera behaviour.</summary>
- public GameObject VirtualCameraGameObject
- {
- get
- {
- if (this == null)
- return null; // object deleted
- return gameObject;
- }
- }
- /// <summary>Returns false if the object has been deleted</summary>
- public bool IsValid { get { return !(this == null); } }
- /// <summary>The CameraState object holds all of the information
- /// necessary to position the Unity camera. It is the output of this class.</summary>
- public abstract CameraState State { get; }
- /// <summary>Support for meta-virtual-cameras. This is the situation where a
- /// virtual camera is in fact the public face of a private army of virtual cameras, which
- /// it manages on its own. This method gets the VirtualCamera owner, if any.
- /// Private armies are implemented as Transform children of the parent vcam.</summary>
- public ICinemachineCamera ParentCamera
- {
- get
- {
- if (!mSlaveStatusUpdated || !Application.isPlaying)
- UpdateSlaveStatus();
- return m_parentVcam;
- }
- }
- /// <summary>Check whether the vcam a live child of this camera.
- /// This base class implementation always returns false.</summary>
- /// <param name="vcam">The Virtual Camera to check</param>
- /// <param name="dominantChildOnly">If truw, will only return true if this vcam is the dominat live child</param>
- /// <returns>True if the vcam is currently actively influencing the state of this vcam</returns>
- public virtual bool IsLiveChild(ICinemachineCamera vcam, bool dominantChildOnly = false) { return false; }
- /// <summary>Get the LookAt target for the Aim component in the Cinemachine pipeline.</summary>
- public abstract Transform LookAt { get; set; }
- /// <summary>Get the Follow target for the Body component in the Cinemachine pipeline.</summary>
- public abstract Transform Follow { get; set; }
- /// <summary>Set this to force the next update to ignore deltaTime and reset itself</summary>
- public virtual bool PreviousStateIsValid { get; set; }
- /// <summary>
- /// Update the camera's state.
- /// The implementation must guarantee against multiple calls per frame, and should
- /// use CinemachineCore.UpdateVirtualCamera(ICinemachineCamera, Vector3, float), which
- /// has protection against multiple calls per frame.
- /// </summary>
- /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
- /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
- public void UpdateCameraState(Vector3 worldUp, float deltaTime)
- {
- CinemachineCore.Instance.UpdateVirtualCamera(this, worldUp, deltaTime);
- }
- /// <summary>Internal use only. Do not call this method.
- /// Called by CinemachineCore at designated update time
- /// so the vcam can position itself and track its targets.
- /// Do not call this method. Let the framework do it at the appropriate time</summary>
- /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
- /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
- public abstract void InternalUpdateCameraState(Vector3 worldUp, float deltaTime);
- /// <summary> Collection of parameters that influence how this virtual camera transitions from
- /// other virtual cameras </summary>
- [Serializable]
- public struct TransitionParams
- {
- /// <summary>Hint for blending positions to and from this virtual camera</summary>
- [Tooltip("Hint for blending positions to and from this virtual camera")]
- [FormerlySerializedAs("m_PositionBlending")]
- public BlendHint m_BlendHint;
- /// <summary>When this virtual camera goes Live, attempt to force the position to be the same as the current position of the Unity Camera</summary>
- [Tooltip("When this virtual camera goes Live, attempt to force the position to be the same as the current position of the Unity Camera")]
- public bool m_InheritPosition;
- /// <summary>This event fires when the virtual camera goes Live</summary>
- [Tooltip("This event fires when the virtual camera goes Live")]
- public CinemachineBrain.VcamActivatedEvent m_OnCameraLive;
- }
- /// <summary>Notification that this virtual camera is going live.
- /// Base class implementation must be called by any overridden method.</summary>
- /// <param name="fromCam">The camera being deactivated. May be null.</param>
- /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
- /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
- public virtual void OnTransitionFromCamera(
- ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
- {
- if (!gameObject.activeInHierarchy)
- PreviousStateIsValid = false;
- }
- /// <summary>Maintains the global vcam registry. Always call the base class implementation.</summary>
- protected virtual void OnDestroy()
- {
- CinemachineCore.Instance.CameraDestroyed(this);
- }
- /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
- protected virtual void OnTransformParentChanged()
- {
- CinemachineCore.Instance.CameraDisabled(this);
- CinemachineCore.Instance.CameraEnabled(this);
- UpdateSlaveStatus();
- UpdateVcamPoolStatus();
- }
- bool m_WasStarted;
- /// <summary>Derived classes should call base class implementation.</summary>
- protected virtual void Start()
- {
- m_WasStarted = true;
- }
- /// <summary>
- /// Called on inactive object when being artificially activated by timeline.
- /// This is necessary because Awake() isn't called on inactive gameObjects.
- /// </summary>
- internal void EnsureStarted()
- {
- if (!m_WasStarted)
- {
- m_WasStarted = true;
- var extensions = GetComponentsInChildren<CinemachineExtension>();
- for (int i = 0; i < extensions.Length; ++i)
- extensions[i].EnsureStarted();
- }
- }
- /// <summary>
- /// Locate the first component that implements AxisState.IInputAxisProvider.
- /// </summary>
- /// <returns>The first AxisState.IInputAxisProvider or null if none</returns>
- public AxisState.IInputAxisProvider GetInputAxisProvider()
- {
- var components = GetComponentsInChildren<MonoBehaviour>();
- for (int i = 0; i < components.Length; ++i)
- {
- var provider = components[i] as AxisState.IInputAxisProvider;
- if (provider != null)
- return provider;
- }
- return null;
- }
- /// <summary>Enforce bounds for fields, when changed in inspector.
- /// Call base class implementation at the beginning of overridden method.
- /// After base method is called, ValidatingStreamVersion will be valid.</summary>
- protected virtual void OnValidate()
- {
- m_OnValidateCalled = true;
- ValidatingStreamVersion = m_StreamingVersion;
- m_StreamingVersion = CinemachineCore.kStreamingVersion;
- }
- /// <summary>Base class implementation adds the virtual camera from the priority queue.</summary>
- protected virtual void OnEnable()
- {
- UpdateSlaveStatus();
- UpdateVcamPoolStatus(); // Add to queue
- if (!CinemachineCore.Instance.IsLive(this))
- PreviousStateIsValid = false;
- CinemachineCore.Instance.CameraEnabled(this);
- // Sanity check - if another vcam component is enabled, shut down
- var vcamComponents = GetComponents<CinemachineVirtualCameraBase>();
- for (int i = 0; i < vcamComponents.Length; ++i)
- {
- if (vcamComponents[i].enabled && vcamComponents[i] != this)
- {
- Debug.LogError(Name
- + " has multiple CinemachineVirtualCameraBase-derived components. Disabling "
- + GetType().Name + ".");
- enabled = false;
- }
- }
- }
- /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
- protected virtual void OnDisable()
- {
- UpdateVcamPoolStatus(); // Remove from queue
- CinemachineCore.Instance.CameraDisabled(this);
- }
- /// <summary>Base class implementation makes sure the priority queue remains up-to-date.</summary>
- protected virtual void Update()
- {
- if (m_Priority != m_QueuePriority)
- UpdateVcamPoolStatus();
- }
- private bool mSlaveStatusUpdated = false;
- private CinemachineVirtualCameraBase m_parentVcam = null;
- private void UpdateSlaveStatus()
- {
- mSlaveStatusUpdated = true;
- m_parentVcam = null;
- Transform p = transform.parent;
- if (p != null)
- {
- #if UNITY_2019_2_OR_NEWER
- p.TryGetComponent(out m_parentVcam);
- #else
- m_parentVcam = p.GetComponent<CinemachineVirtualCameraBase>();
- #endif
- }
- }
- /// <summary>Returns this vcam's LookAt target, or if that is null, will retrun
- /// the parent vcam's LookAt target.</summary>
- /// <param name="localLookAt">This vcam's LookAt value.</param>
- /// <returns>The same value, or the parent's if null and a parent exists.</returns>
- protected Transform ResolveLookAt(Transform localLookAt)
- {
- Transform lookAt = localLookAt;
- if (lookAt == null && ParentCamera != null)
- lookAt = ParentCamera.LookAt; // Parent provides default
- return lookAt;
- }
- /// <summary>Returns this vcam's Follow target, or if that is null, will retrun
- /// the parent vcam's Follow target.</summary>
- /// <param name="localFollow">This vcam's Follow value.</param>
- /// <returns>The same value, or the parent's if null and a parent exists.</returns>
- protected Transform ResolveFollow(Transform localFollow)
- {
- Transform follow = localFollow;
- if (follow == null && ParentCamera != null)
- follow = ParentCamera.Follow; // Parent provides default
- return follow;
- }
- private int m_QueuePriority = int.MaxValue;
- private void UpdateVcamPoolStatus()
- {
- CinemachineCore.Instance.RemoveActiveCamera(this);
- if (m_parentVcam == null && isActiveAndEnabled)
- CinemachineCore.Instance.AddActiveCamera(this);
- m_QueuePriority = m_Priority;
- }
- /// <summary>When multiple virtual cameras have the highest priority, there is
- /// sometimes the need to push one to the top, making it the current Live camera if
- /// it shares the highest priority in the queue with its peers.
- ///
- /// This happens automatically when a
- /// new vcam is enabled: the most recent one goes to the top of the priority subqueue.
- /// Use this method to push a vcam to the top of its priority peers.
- /// If it and its peers share the highest priority, then this vcam will become Live.</summary>
- public void MoveToTopOfPrioritySubqueue()
- {
- UpdateVcamPoolStatus();
- }
- /// <summary>This is called to notify the component that a target got warped,
- /// so that the component can update its internal state to make the camera
- /// also warp seamlessy.</summary>
- /// <param name="target">The object that was warped</param>
- /// <param name="positionDelta">The amount the target's position changed</param>
- public virtual void OnTargetObjectWarped(Transform target, Vector3 positionDelta)
- {
- // inform the extensions
- if (mExtensions != null)
- {
- for (int i = 0; i < mExtensions.Count; ++i)
- mExtensions[i].OnTargetObjectWarped(target, positionDelta);
- }
- }
- /// <summary>
- /// Force the virtual camera to assume a given position and orientation
- /// </summary>
- /// <param name="pos">Worldspace pposition to take</param>
- /// <param name="rot">Worldspace orientation to take</param>
- public virtual void ForceCameraPosition(Vector3 pos, Quaternion rot)
- {
- // inform the extensions
- if (mExtensions != null)
- {
- for (int i = 0; i < mExtensions.Count; ++i)
- mExtensions[i].ForceCameraPosition(pos, rot);
- }
- }
-
- /// <summary>Create a blend between 2 virtual cameras, taking into account
- /// any existing active blend.</summary>
- protected CinemachineBlend CreateBlend(
- ICinemachineCamera camA, ICinemachineCamera camB,
- CinemachineBlendDefinition blendDef,
- CinemachineBlend activeBlend)
- {
- if (blendDef.BlendCurve == null || blendDef.BlendTime <= 0 || (camA == null && camB == null))
- return null;
- if (activeBlend != null)
- {
- // Special case: if backing out of a blend-in-progress
- // with the same blend in reverse, adjust the belnd time
- if (activeBlend.CamA == camB
- && activeBlend.CamB == camA
- && activeBlend.Duration <= blendDef.BlendTime)
- {
- blendDef.m_Time = activeBlend.TimeInBlend;
- }
- camA = new BlendSourceVirtualCamera(activeBlend);
- }
- else if (camA == null)
- camA = new StaticPointVirtualCamera(State, "(none)");
- return new CinemachineBlend(
- camA, camB, blendDef.BlendCurve, blendDef.BlendTime, 0);
- }
- /// <summary>
- /// Create a camera state based on the current transform of this vcam
- /// </summary>
- /// <param name="worldUp">Current World Up direction, as provided by the brain</param>
- /// <param name="lens">Lens settings to serve as base, will be combined with lens from brain, if any</param>
- /// <returns></returns>
- protected CameraState PullStateFromVirtualCamera(Vector3 worldUp, ref LensSettings lens)
- {
- CameraState state = CameraState.Default;
- state.RawPosition = TargetPositionCache.GetTargetPosition(transform);
- state.RawOrientation = TargetPositionCache.GetTargetRotation(transform);
- state.ReferenceUp = worldUp;
- CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(this);
- if (brain != null)
- lens.SnapshotCameraReadOnlyProperties(brain.OutputCamera);
- state.Lens = lens;
- return state;
- }
- }
- }
|