Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Camera not being set on state driven camera and blend tree

Discussion in 'Cinemachine' started by Telojuri94, Mar 19, 2019.

  1. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    Hi! I'm having a problem with the state driven camera component and the blend trees. The structure on the cameras is this one:

    upload_2019-3-19_9-40-13.png

    And the animator structure is the next one:

    upload_2019-3-19_9-41-5.png

    Both motion and Crouch Motion are Blend trees, but as you can see, the crouch motion animations use the same camera, while the standard motion animations use a different camera for the sprint animation. The problem is that if I go to the crouch state, the crouch camera is set, but if I return to the motion state, the crouch camera remains until I start moving.



    As you can see, when the character crouch, the camera changes to the crouch camera, but if the player stands, the camera remains in crouch. You can also see that if the player is walking and stands while walking, the camera changes correctly.

    You know what could it be?

    Thank you!
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    3,811
    I'm guessing that when the character stands up, it enters a state that is not covered specifically in your SDC instruction set. In that case, it just holds the current vcam until a state with a vcam instruction is encountered.

    Try adding an instruction for "Motion". That will serve as the default for all the states under Motion, then you can override specific substates (e.g. sprint).
     
  3. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    I tried to add the general Motion state camera and the crouch/motion transition works well now, but is not working with the Motion/Motion.Sprint as you said.

    The settings of the CM State driven camera is the following:

    upload_2019-3-20_12-9-5.png

    The behaviour is the following:



    As you can see, the Motion camera lerps to the Sprint camera, but it returns to the Motion camera. It's like the motion camera is overriding the Sprint camera. I also tried to change the priority of the cameras but it didn't changed anything.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    3,811
    Maybe you can add some debugging logs to log the current animation state. Also check the Show Debug Text checkbox on the SDC, to get a display of the current active child vcam.
     
  5. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7

    Here it is. The Motion animations are Idle_Left, Idle_Right, Run and Sprint, and the camera should change on Sprint animation.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    3,811
    Looking at the debug text, it seems that the sprint camera gets activated, but then is immediately overruled when your state machine goes into another state. It seems that you're not attaching the sprint cam to the right state.

    upload_2019-3-20_11-4-54.png

    Can you also show an output of what the animation state machine is doing?
     
  7. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    Here you have the video with the animator playing at it's side:



    This is the State driven camera component
    upload_2019-3-20_16-22-9.png
     
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    3,811
    Can you export this scene as a unitypackage and send it to me? I'm going to have to look a little deeper to understand what's happening
     
  9. Telojuri94

    Telojuri94

    Joined:
    Jan 25, 2017
    Posts:
    7
    I'm sorry Gregoryl, but I can't share the scene because confidentiality reasons. But trying to replicate the problem I found something. That's the structure of the blend tree:

    upload_2019-3-20_17-4-57.png

    I have the Sprint animation placed on 1.4, and is when horizontal_movement reaches exactly 1.4 when it returns to the Motion camera for some reason. I've noticed that if i put the Sprint animation on 1.41, considering that I coded that horizontal_movement can just reach 1.4, it works well.
    Basically, the problem only appears when the variable reaches exactly the threshold.
     
  10. Kelevra

    Kelevra

    Joined:
    Dec 27, 2012
    Posts:
    65
    Hi there. Looks like no one has found this bug but it's still there. I hope this will help you to fix it.

    Hello @Gregoryl
    The problem is in how you are choosing state hash. When you querying a state from a blend tree, as I understood, it will return you all weighed clips so when there is only one clip left it will return the only one. So when you checking "GetAnimatorClipInfoCount" and there is only one clip you are taking hash from fullPathHash which contains a hash for the parent state. That's why the current state evaluated in that order Movement(run is weighed most) -> Movement.Sprint (Sprint is in blend with a run but weighed most) -> Movement (Sprint is one left, but we are suddenly using a parent hash)

    This is the reason why it has worked for @Telojuri94 when he didn't fully blend his sprint animation.

    CinemachineStateDrivenCamera.cs
    ChooseCurrentCamera
    Code (CSharp):
    1. // Get the current state
    2.             int hash;
    3.             if (m_AnimatedTarget.IsInTransition(m_LayerIndex))
    4.             {
    5.                 // Force "current" state to be the state we're transitionaing to
    6.                 AnimatorStateInfo info = m_AnimatedTarget.GetNextAnimatorStateInfo(m_LayerIndex);
    7.                 hash = info.fullPathHash;
    8.                 if (m_AnimatedTarget.GetNextAnimatorClipInfoCount(m_LayerIndex) > 1)
    9.                 {
    10.                     m_AnimatedTarget.GetNextAnimatorClipInfo(m_LayerIndex, m_clipInfoList);
    11.                     hash = GetClipHash(info.fullPathHash, m_clipInfoList);
    12.                 }
    13.             }
    14.             else
    15.             {
    16.                 AnimatorStateInfo info = m_AnimatedTarget.GetCurrentAnimatorStateInfo(m_LayerIndex);
    17.                 hash = info.fullPathHash;
    18.                 if (m_AnimatedTarget.GetCurrentAnimatorClipInfoCount(m_LayerIndex) > 1)
    19.                 {
    20.                     m_AnimatedTarget.GetCurrentAnimatorClipInfo(m_LayerIndex, m_clipInfoList);
    21.                     hash = GetClipHash(info.fullPathHash, m_clipInfoList);
    22.                 }
    23.             }
    Fast fix:
    Code (CSharp):
    1. // Get the current state
    2.             int hash;
    3.             if (m_AnimatedTarget.IsInTransition(m_LayerIndex))
    4.             {
    5.                 // Force "current" state to be the state we're transitionaing to
    6.                 AnimatorStateInfo info = m_AnimatedTarget.GetNextAnimatorStateInfo(m_LayerIndex);
    7.  
    8.                 m_AnimatedTarget.GetNextAnimatorClipInfo(m_LayerIndex, m_clipInfoList);
    9.                 hash = GetClipHash(info.fullPathHash, m_clipInfoList);
    10.             }
    11.             else
    12.             {
    13.                 AnimatorStateInfo info = m_AnimatedTarget.GetCurrentAnimatorStateInfo(m_LayerIndex);
    14.  
    15.                 m_AnimatedTarget.GetCurrentAnimatorClipInfo(m_LayerIndex, m_clipInfoList);
    16.                 hash = GetClipHash(info.fullPathHash, m_clipInfoList);
    17.             }
    18.  
    19.             // Check if we have an instruction for that clip.
    20.             if (m_clipInfoList.Count == 1)
    21.             {
    22.                 var fakeHash = LookupFakeHash(hash, m_clipInfoList[0].clip);
    23.                 if (mInstructionDictionary.ContainsKey(fakeHash))
    24.                 {
    25.                     hash = fakeHash;
    26.                 }
    27.             }
     
    Last edited: Jun 24, 2020
    Gregoryl likes this.
  11. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    3,811
    Hey @Kelevra,
    Thanks for this post! I will look into the issue
     
unityunity