Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug AnimationScriptPlayable cannot strip the velocity of its input

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

  1. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    229
    I tried to input an
    AnimationClipPlayable
    into an
    AnimationScriptPlayable
    and set the
    AnimationStream.velocity
    to
    Vector3.zero
    in the
    AnimationScriptPlayable.ProcessRootMotion
    method to remove the displacement in the AnimationClip. However, this approach did not work as expected. Although
    AnimationStream.velocity
    did become
    Vector3.zero
    , the character still moved, and in the
    OnAnimatorMove
    method,
    Animator.velocity
    was also not
    Vector3.zero
    .

    Why are
    AnimationStream.velocity
    and
    Animator.velocity
    not equal (without any animation blending)?

    What is the relationship between the RootMotion generated in the AnimationClip and
    AnimationStream.velocity
    ? Is it that the RootMotion in the clip is converted to velocity and carried by
    AnimationStream
    to be passed up the Playable tree? Or is there additional data that caused me to change
    AnimationStream.velocity
    but not affect the final RootMotion?

    If the approach of handling RootMotion with
    AnimationScriptPlayable
    does not work, do I need to handle RootMotion in
    OnAnimatorMove
    instead? In this case, should I directly extract
    Animator.velocity
    , multiply it by
    deltaTime
    , and add it to the Transform? If our character uses
    Rigidbody
    , should we modify
    Rigidbody.velocity
    instead of modifying Transform?

    Here is the test code (also attached by file):
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Animations;
    3. using UnityEngine.Playables;
    4. using UnityEngine.UI;
    5.  
    6. // AnimationScriptPlayable cannot strip the velocity and angularVelocity of its input
    7. // See comment in `AnimJobTest.OnAnimatorMove`
    8.  
    9. [RequireComponent(typeof(Animator))]
    10. public class AnimJobTest : MonoBehaviour
    11. {
    12.     public AnimationClip clip;
    13.     public Text text;
    14.  
    15.     private Animator _animator;
    16.     private PlayableGraph _graph;
    17.     private Vector3 _prevPos;
    18.  
    19.  
    20.     // Window/Analysis/PlayableGraph Monitor
    21.     // https://github.com/SolarianZ/UnityPlayableGraphMonitorTool
    22.  
    23.     private void Start()
    24.     {
    25.         _animator = GetComponent<Animator>();
    26.         _graph = PlayableGraph.Create(nameof(AnimJobTest));
    27.         _graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
    28.  
    29.         var animClipPlayable = AnimationClipPlayable.Create(_graph, clip);
    30.  
    31.         var animScriptPlayableA = AnimationScriptPlayable.Create(_graph, new MyAnimJobA());
    32.         animScriptPlayableA.AddInput(animClipPlayable, 0, 1f);
    33.  
    34.         var animScriptPlayableB = AnimationScriptPlayable.Create(_graph, new MyAnimJobB());
    35.         animScriptPlayableB.AddInput(animScriptPlayableA, 0, 1f);
    36.  
    37.         var animOutput = AnimationPlayableOutput.Create(_graph, "AnimOutput", _animator);
    38.         animOutput.SetSourcePlayable(animScriptPlayableB);
    39.  
    40.         _graph.Play();
    41.     }
    42.  
    43.     // private void OnAnimatorMove()
    44.     // {
    45.     //     // Theoretically, the `FINAL_VEL` should be zero, because it has been stripped in `MyAnimJobA.ProcessRootMotion`,
    46.     //     // and in `MyAnimJobB.ProcessRootMotion` , the `JOB_B_VEL_0` is indeed zero.
    47.     //     // However, the `FINAL_VEL` is actually a non-zero value, close to the `JOB_A_VEL_1`.
    48.     //
    49.     //     // Only used to view values during breakpoint debugging
    50.     //     var velocity = _animator.velocity; // FINAL_VEL
    51.     //     var deltaPosition = _animator.deltaPosition;
    52.     //     var rootPosition = _animator.rootPosition;
    53.     //     var targetPosition = _animator.targetPosition;
    54.     //     var pivotPosition = _animator.pivotPosition;
    55.     //     // var bodyPosition = _animator.bodyPosition;
    56.     //
    57.     //     _animator.ApplyBuiltinRootMotion();
    58.     // }
    59.  
    60.     private void LateUpdate()
    61.     {
    62.         var currPos = transform.position;
    63.         var posChanged = (_prevPos - currPos).sqrMagnitude > Mathf.Epsilon;
    64.         _prevPos = currPos;
    65.  
    66.         text.text = posChanged ? "Has Motion" : "No Motion";
    67.         text.color = posChanged ? Color.red : Color.green;
    68.     }
    69.  
    70.     private void OnDestroy()
    71.     {
    72.         if (_graph.IsValid()) _graph.Destroy();
    73.     }
    74. }
    75.  
    76. public struct MyAnimJobA : IAnimationJob
    77. {
    78.     public void ProcessRootMotion(AnimationStream stream)
    79.     {
    80.         // var input = stream.GetInputStream(0);
    81.         // var inputVelocity = input.velocity;
    82.         // var inputPosition = input.rootMotionPosition;
    83.  
    84.         // Only used to view values during breakpoint debugging
    85.         var velocity = stream.velocity; // JOB_A_VEL_0
    86.         var position = stream.rootMotionPosition;
    87.  
    88.         stream.velocity = Vector3.zero;
    89.         stream.angularVelocity = Vector3.zero;
    90.  
    91.         // Only used to view values during breakpoint debugging
    92.         var newVelocity = stream.velocity; // JOB_A_VEL_1
    93.         var newPosition = stream.rootMotionPosition;
    94.     }
    95.  
    96.     public void ProcessAnimation(AnimationStream stream)
    97.     {
    98.     }
    99. }
    100.  
    101. public struct MyAnimJobB : IAnimationJob
    102. {
    103.     public void ProcessRootMotion(AnimationStream stream)
    104.     {
    105.         // var input = stream.GetInputStream(0);
    106.         // var inputVelocity = input.velocity;
    107.         // var inputPosition = input.rootMotionPosition;
    108.  
    109.         // Only used to view values during breakpoint debugging
    110.         var velocity = stream.velocity; // JOB_B_VEL_0
    111.         var position = stream.rootMotionPosition;
    112.     }
    113.  
    114.     public void ProcessAnimation(AnimationStream stream)
    115.     {
    116.     }
    117. }
     

    Attached Files:

  2. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    229
    The topology of the PlayableGraph:

    upload_2023-3-10_20-20-23.png
     
  3. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    229
  4. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    229