Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question How to make Cinemachine complete current blending immediately?

Discussion in 'Cinemachine' started by SolarianZ, Jun 24, 2021.

  1. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    I'm trying to make my cinemachine camera complete its current blending immediately, I have tried to set "cinemachineBrain.ActiveBlend.TimeInBlend" , call "cinemachineBrain.ActiveBlend.UpdateCameraState()" and even tried to invoke "cinemachineBrain.SetCameraOverride()" by Reflection, but non of them worked.
    Anyone can help? :)

    upload_2021-6-24_23-3-46.png
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    You can cut to another vcam. That will interrupt a blend.
    You can also use the SoloCamera static property of the brain. That's a cheat, but it will work.
     
  3. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    I can set CinemahicneBrain's default blend to Cut, but I do not know if current blending cameras have a custom blend.
    And solo camera just cover up the blend but not complete the blend, if I remove solo state, cinemachine will back to blending.
    Why there is not a method to complete blending immediately? It's really use useful.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    Yes, I see the issue. Thanks for bringing it up. I will add a feature request for this.
     
    iendsl likes this.
  5. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    Thank you! And could you please also add "Increase special virtual camera's priority and activate it without blending" to your feature list.
     
  6. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    And I want to modify the source code of Cinemachine to implement this feature, can you give some tips? Thanks!
     
  7. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    I'm not sure I understand this request. Are you asking for a feature to temporarily override a blend setting for a vcam? If so, this feature already exists. See CinemachineCore.GetBlendOverride.

    You can add a setter to CinemachineBrain.ActiveBlend, like this (in CinemachineBrain.cs):
    Code (CSharp):
    1.         public CinemachineBlend ActiveBlend
    2.         {
    3.             get
    4.             {
    5.                 if (SoloCamera != null)
    6.                     return null;
    7.                 if (mCurrentLiveCameras.CamA == null || mCurrentLiveCameras.IsComplete)
    8.                     return null;
    9.                 return mCurrentLiveCameras;
    10.             }
    11.             set
    12.             {
    13.                 if (value == null)
    14.                     mFrameStack[0].blend.Duration = 0;
    15.                 else
    16.                     mFrameStack[0].blend = value;
    17.             }
    18.         }
    To use it to force a blend to finish, do something like this:
    Code (CSharp):
    1. brain.ActiveBlend = null;
     
  8. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    I'm trying to using this method, but it seems to be waiting a frame to cut cameras, therefore I will get a flicker on screen. Is there any way to make Cinemachine flush cameras state in same frame?
     
  9. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    What happens if you call CinemachineBrain.ManualUpdate?
     
  10. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    wow! I'm using cinemachine 2.5.0, I'm going to upgrade to new version right now! Thank you.:)
     
    Gregoryl likes this.
  11. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    Re-edited: some bug fixes.

    I implemented this feature by make class CinemachineBrain partial and add two extra methods:

    Code (CSharp):
    1.  
    2. namespace Cinemachine
    3. {
    4.     public partial class CinemachineBrain
    5.     {
    6.         /// <summary>
    7.         /// Call this method explicitly from an external script to update the virtual cameras
    8.         /// and position the main camera, if the UpdateMode is set to ManualUpdate.
    9.         /// For other update modes, this method is called automatically, and should not be
    10.         /// called from elsewhere.
    11.         /// </summary>
    12.         public void ManualUpdate(float deltaTime)
    13.         {
    14.             if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
    15.                 UpdateFrame0(deltaTime);
    16.  
    17.             ComputeCurrentBlend(ref mCurrentLiveCameras, 0);
    18.  
    19.             if (m_UpdateMethod == UpdateMethod.FixedUpdate)
    20.             {
    21.                 // Special handling for fixed update: cameras that have been enabled
    22.                 // since the last physics frame must be updated now
    23.                 if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
    24.                 {
    25.                     CinemachineCore.Instance.CurrentUpdateFilter = CinemachineCore.UpdateFilter.Fixed;
    26.                     if (SoloCamera == null)
    27.                         mCurrentLiveCameras.UpdateCameraState(
    28.                             DefaultWorldUp, GetEffectiveDeltaTime(true));
    29.                 }
    30.             }
    31.             else
    32.             {
    33.                 CinemachineCore.UpdateFilter filter = CinemachineCore.UpdateFilter.Late;
    34.                 if (m_UpdateMethod == UpdateMethod.SmartUpdate)
    35.                 {
    36.                     // Track the targets
    37.                     UpdateTracker.OnUpdate(UpdateTracker.UpdateClock.Late);
    38.                     filter = CinemachineCore.UpdateFilter.SmartLate;
    39.                 }
    40.                 UpdateVirtualCameras(filter, deltaTime);
    41.             }
    42.  
    43.             // Choose the active vcam and apply it to the Unity camera
    44.             if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
    45.                 ProcessActiveCamera(deltaTime);
    46.         }
    47.  
    48.         /// <summary>
    49.         /// Complete current active blend immediately.
    50.         /// </summary>
    51.         /// <param name="completeDamp">If true, will also complete aim and body damp.</param>
    52.         public void CompleteCurrentBlend(bool completeDamp = true)
    53.         {
    54.             if (mFrameStack.Count == 0)
    55.             {
    56.                 return;
    57.             }
    58.  
    59.             // Complete current blend
    60.             mFrameStack[0].blend.Duration = 0;
    61.             ManualUpdate();
    62.  
    63.             // Use -1 to prevent dolly camera finds closest point
    64.             var deltaTime = -1;
    65.             CinemachineCore.UpdateFilter filter = CinemachineCore.UpdateFilter.Late;
    66.             if (m_UpdateMethod == UpdateMethod.SmartUpdate)
    67.             {
    68.                 // Track the targets
    69.                 UpdateTracker.OnUpdate(UpdateTracker.UpdateClock.Late);
    70.                 filter = CinemachineCore.UpdateFilter.SmartLate;
    71.             }
    72.             UpdateVirtualCameras(filter, deltaTime);
    73.  
    74.             // Choose the active vcam and apply it to the Unity camera
    75.             if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
    76.                 ProcessActiveCamera(deltaTime);
    77.  
    78.             // Complete damp
    79.             if (completeDamp && ActiveVirtualCamera is CinemachineVirtualCameraBase vcam)
    80.             {
    81.                 vcam.PreviousStateIsValid = false;
    82.                 ManualUpdate();
    83.             }
    84.         }
    85.  
    86.         /// <summary>
    87.         /// Complete incoming active blend immediately if the incoming blend is between camA and camB or contains camA or camB.
    88.         /// </summary>
    89.         /// <param name="appointCamera">If not null, will only take effect when top priority camera equals appointCamera.</param>
    90.         /// <param name="completeDamp">If true, will also complete aim and body damp.</param>
    91.         public void CompleteIncomingBlend(CinemachineVirtualCameraBase appointCamera = null, bool completeDamp = true)
    92.         {
    93.             if (mFrameStack.Count == 0)
    94.             {
    95.                 return;
    96.             }
    97.  
    98.             if (appointCamera)
    99.             {
    100.                 appointCamera.MoveToTopOfPrioritySubqueue();
    101.             }
    102.  
    103.             // Find new active camera
    104.             var topCam = ActiveVirtualCamera as CinemachineVirtualCameraBase;
    105.             int numCameras = CinemachineCore.Instance.VirtualCameraCount;
    106.             for (int i = 0; i < numCameras; ++i)
    107.             {
    108.                 var cam = CinemachineCore.Instance.GetVirtualCamera(i);
    109.                 if (cam.gameObject.scene != gameObject.scene)
    110.                 {
    111.                     continue;
    112.                 }
    113.  
    114.                 if (!topCam || topCam.gameObject.scene != gameObject.scene || topCam.Priority < cam.Priority)
    115.                 {
    116.                     topCam = cam;
    117.                 }
    118.  
    119.                 // When call MoveToTopOfPrioritySubqueue() and ManualUpdate(),
    120.                 // cameras in mActiveCameras may out of order, so do not break
    121.                 //if (topCam.Priority >= cam.Priority)
    122.                 //{
    123.                 //    break;
    124.                 //}
    125.             }
    126.             if (topCam == null || (appointCamera && appointCamera != topCam))
    127.             {
    128.                 return;
    129.             }
    130.  
    131.             // Trigger virtual cameras priority queen update
    132.             topCam.MoveToTopOfPrioritySubqueue();
    133.  
    134.             // Update frame stack
    135.             UpdateFrame0(0);
    136.  
    137.             // Complete blend
    138.             CompleteCurrentBlend(completeDamp);
    139.         }
    140.     }
    141.  
    142.     public static class CinemachineCameraExtension
    143.     {
    144.         /// <summary>
    145.         /// Complete body and aim damp.
    146.         /// </summary>
    147.         /// <param name="cmCam"></param>
    148.         public static void CompleteDamps(this ICinemachineCamera cmCam)
    149.         {
    150.             if (cmCam is CinemachineVirtualCameraBase vcam)
    151.             {
    152.                 vcam.PreviousStateIsValid = false;
    153.             }
    154.         }
    155.     }
    156. }
    157.  
     
    Last edited: Jul 16, 2021
    xVergilx likes this.
  12. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,041
    I've hit the same issue with blends but rather clearing all blends completely and this helped. Thanks.

    One more thing though, to prevent "Mid-Blend" from occuring in rare cases, mFrameStack has to be cleared as well:
    Code (CSharp):
    1.         public void CompleteCurrentBlend(bool completeDamp = true)
    2.         {
    3.             if (mFrameStack.Count == 0)
    4.             {
    5.                 return;
    6.             }
    7.             // Complete current blend
    8.             mFrameStack[0].blend.Duration = 0;
    9.             ManualUpdate();
    10.             // Use -1 to prevent dolly camera finds closest point
    11.             var deltaTime = -1;
    12.             CinemachineCore.UpdateFilter filter = CinemachineCore.UpdateFilter.Late;
    13.             if (m_UpdateMethod == UpdateMethod.SmartUpdate)
    14.             {
    15.                 // Track the targets
    16.                 UpdateTracker.OnUpdate(UpdateTracker.UpdateClock.Late);
    17.                 filter = CinemachineCore.UpdateFilter.SmartLate;
    18.             }
    19.             UpdateVirtualCameras(filter, deltaTime);
    20.             // Choose the active vcam and apply it to the Unity camera
    21.             if (m_BlendUpdateMethod != BrainUpdateMethod.FixedUpdate)
    22.                 ProcessActiveCamera(deltaTime);
    23.             // Complete damp
    24.             if (completeDamp && ActiveVirtualCamera is CinemachineVirtualCameraBase vcam)
    25.             {
    26.                 vcam.PreviousStateIsValid = false;
    27.                 ManualUpdate();
    28.             }
    29.          
    30.             mFrameStack.Clear();
    31.         }
     
    Unifikation and SolarianZ like this.
  13. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    Hi! Is there any news about this feature request?
     
    sarelmicha93 likes this.
  14. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    Yes, in the latest CM, you can set brain.ActiveBlend = null to complete the current blend.
     
    SolarianZ likes this.
  15. gferrari

    gferrari

    Joined:
    Jan 14, 2015
    Posts:
    135
    hi, is readonly,

    cinemachineBrain.ActiveBlend = null;
     
  16. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    184
    Gregoryl and gferrari like this.
  17. TomTheMan59

    TomTheMan59

    Joined:
    Mar 8, 2021
    Posts:
    216
    I don't want to necro this thread, but the issue still remains.

    brain.ActiveBlend = null does NOT work.
    Screenshot 2023-05-03 at 12.55.08 PM.png

    Screenshot 2023-05-03 at 12.55.42 PM.png

    Please, I am banging my head against the desk trying to find a simple way to cut to another vcam while the default blend is happening.

    This seems overly complicated to just do that =(
     
  18. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    Would it work for you to set up a custom blend asset overriding the default blend for the camera you want to cut to, like this?

    upload_2023-5-3_13-31-22.png
     
  19. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    6,871
    When I look at the CM 2.9.5 code, I see that brain.ActiveBlend = null should work. Perhaps your IDE needs refreshing.
     
    TomTheMan59 likes this.