Search Unity

Resolved How can I set the time of the AnimationClipPlayable without affecting the character's position?

Discussion in 'Animation' started by SolarianZ, Mar 6, 2023.

  1. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    I am trying to make a simple animation player and I need to jump to the specified progress of animation clip. However, when I call
    clipPlayable.SetTime(myTime)
    , it not only sets the clip to the specified progress, but also applies the cumulative displacement of the delta time to the character. Is there any way to set the time of the AnimationClipPlayable without affecting the character's position?

    upload_2023-3-6_19-40-12.gif

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Animations;
    3. using UnityEngine.Assertions;
    4. using UnityEngine.Playables;
    5.  
    6. [RequireComponent(typeof(Animator))]
    7. public class AnimClipTest : MonoBehaviour
    8. {
    9.     public AnimationClip walkClip;
    10.     public bool resetWalkTime;
    11.  
    12.     private PlayableGraph _graph;
    13.     private AnimationClipPlayable _walkPlayable;
    14.  
    15.     private void Start()
    16.     {
    17.         Assert.IsTrue(walkClip);
    18.         _graph = PlayableGraph.Create(nameof(AnimClipTest));
    19.         _walkPlayable = AnimationClipPlayable.Create(_graph, walkClip);
    20.         var animOutput = AnimationPlayableOutput.Create(_graph, "AnimOutput", GetComponent<Animator>());
    21.         animOutput.SetSourcePlayable(_walkPlayable);
    22.         _graph.Play();
    23.     }
    24.  
    25.     private void Update()
    26.     {
    27.         if (resetWalkTime)
    28.         {
    29.             resetWalkTime = false;
    30.             _walkPlayable.SetTime(0);
    31.         }
    32.     }
    33.  
    34.     private void OnDestroy()
    35.     {
    36.         if (_graph.IsValid())
    37.         {
    38.             _graph.Destroy();
    39.         }
    40.     }
    41. }
     
    Last edited: Mar 6, 2023
  2. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    In the SimpleAnimation project, Unity provides a simple but imperfect solution which involves calling the SetTime method twice on AnimationClipPlayable.

    The reference link for this solution can be found at https://github.com/Unity-Technologi...nimationComponent/CustomPlayableExtensions.cs .

    Using this method, it can be seen that the character still experiences a slight rewind as shown in the attached image:
    upload_2023-3-28_11-23-1.gif


    To achieve a better result, I chose a slightly more complex solution.

    I input each AnimationClipPlayable into an AnimationScriptPlayable (referred to as ASP) which selects whether or not to strip the current frame's animation RootMotion data.

    At the end of the PlayableGraph's animation tree, I also connected an AnimationScriptPlayable (referred to as RootASP) which extracts the RootMotion data from the AnimationStream.

    Finally, in the character's OnAnimatorMove method, I add the RootASP's RootMotion data to the character's transform. The rough code is shown below:

    Code (CSharp):
    1. // ASP
    2. public struct AnimClipProcessorJob : IAnimationJob
    3. {
    4.     public NativeReference<bool> m_stripRootMotionOnceRef;
    5.  
    6.     public void ProcessRootMotion(AnimationStream stream)
    7.     {
    8.         if (m_stripRootMotionOnceRef.IsCreated && m_stripRootMotionOnceRef.Value)
    9.         {
    10.             stream.velocity = Vector3.zero;
    11.             stream.angularVelocity = Vector3.zero;
    12.             m_stripRootMotionOnceRef.Value = false;
    13.         }
    14.     }
    15.  
    16.     public void ProcessAnimation(AnimationStream stream) {}
    17. }
    18.  
    19. // RootASP
    20. public struct AnimGraphRootJob : IAnimationJob
    21. {
    22.     public NativeReference<Vector3> m_velocityRef;
    23.     public NativeReference<Vector3> m_angularVelocityRef;
    24.     public NativeReference<float> m_deltaTimeRef;
    25.  
    26.     public void ProcessRootMotion(AnimationStream stream)
    27.     {
    28.         m_velocityRef.Value = stream.velocity;
    29.         m_angularVelocityRef.Value = stream.angularVelocity;
    30.         m_deltaTimeRef.Value = stream.deltaTime;
    31.     }
    32.  
    33.     public void ProcessAnimation(AnimationStream stream) {}
    34. }
    35.  
    36. // OnAnimatorMove
    37. private void OnAnimatorMove()
    38. {
    39.     m_animator.ApplyComponentSpaceVelocity(m_velocityRef.Value, m_angularVelocityRef.Value, m_deltaTimeRef.Value);
    40. }
    41.  
    42. public static void ApplyComponentSpaceVelocity(this Animator target,
    43.     Vector3 compSpaceVelocity, Vector3 compSpaceAngularVelocityInRadian, float deltaTime)
    44. {
    45.     var compSpaceDeltaRotation = Quaternion.Euler(compSpaceAngularVelocityInRadian * Mathf.Rad2Deg * deltaTime);
    46.     var worldSpaceDeltaPosition = target.transform.TransformDirection(compSpaceVelocity) * deltaTime;
    47.     target.transform.rotation *= compSpaceDeltaRotation;
    48.     target.transform.position += worldSpaceDeltaPosition;
    49. }
    The final result:
    upload_2023-3-28_11-25-23.gif
    upload_2023-3-28_11-25-30.gif
     
    tsukimi likes this.
  3. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    By the way, I would like to mention that after stripping the RootMotion data in the ASP, the RootMotion data obtained from the Animator in the OnAnimatorMove method is INCONSISTENT with the data extracted from the AnimationStream in the RootASP. Therefore, the OnAnimatorMove method cannot use the data obtained from the Animator.

    I mentioned this problem in a previous thread but did not receive a reply. I would be grateful if anyone could provide an explanation for this issue.
     
    Last edited: Mar 29, 2023
  4. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    The simplified topological structure of PlayableGraph:
    upload_2023-3-28_11-43-30.png
     
  5. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Unity has confirmed this is a bug: https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-33177
     
  6. janicelester

    janicelester

    Joined:
    Apr 19, 2023
    Posts:
    1
    I am having the same issue. Fortunately, I find your post. Thanks.
     
    SolarianZ likes this.
  7. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Yuchen_Chang likes this.