Search Unity

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:
    237
    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:
    7,711
    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:
    237
    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:
    7,711
    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:
    237
    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:
    237
    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:
    7,711
    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:
    237
    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:
    7,711
    What happens if you call CinemachineBrain.ManualUpdate?
     
  10. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    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:
    237
    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, deltaTime);
    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: Mar 21, 2024
    xVergilx likes this.
  12. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    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:
    237
    Hi! Is there any news about this feature request?
     
    sarelmicha93 likes this.
  14. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Yes, in the latest CM, you can set brain.ActiveBlend = null to complete the current blend.
     
    nytcj and SolarianZ like this.
  15. gferrari

    gferrari

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

    cinemachineBrain.ActiveBlend = null;
     
  16. SolarianZ

    SolarianZ

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

    TomTheMan59

    Joined:
    Mar 8, 2021
    Posts:
    356
    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:
    7,711
    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:
    7,711
    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.