Search Unity

Resolved Manual Evaluation doesn't work

Discussion in 'Animation Rigging' started by rile-s, Jun 30, 2022.

  1. rile-s

    rile-s

    Joined:
    Sep 18, 2019
    Posts:
    26
    I'm trying to achieve a visual style in my game and the animations are required to run at 24 fps, not at game time. Setting both the animator's and the rig's playable graphs to manual and evaluating them myself doesn't work though. Updating properties in editor or via script just resets the value to it's starting value. Is there anyway to manually tick the rigging?
     
  2. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    We provided new API in Animation Rigging v. 1.2.0 to evaluate the RigBuilder manually. Have a look at the doc for RigBuilder.Evaluate. There is a code example attached that should illustrate how you can setup your RigBuilder and evaluate it manually.
     
  3. rile-s

    rile-s

    Joined:
    Sep 18, 2019
    Posts:
    26
    I upgraded the package but manually evaluating the rig using the new method doesn't work. It updates for one frame then stops, even without the custom fps setup. The example script included doesn't work either.
     
  4. rile-s

    rile-s

    Joined:
    Sep 18, 2019
    Posts:
    26
    To provide more information, my animation setup is made of two animators. A main one and the other has a subset of animations. The RigBuilder helps with combining the two animations. But doesn't work when manually evaluated.

    The function I am using is updated at the specified frame rate (24)
    Code (CSharp):
    1.  
    2. private void UpdateFPS(float time) {
    3.     // Time is 1f / 24f
    4.  
    5.     // Weight changes and such
    6.  
    7.     mainAnimator.playableGraph.Evaluate(time);
    8.     if (otherAnimator.runtimeAnimatorController)
    9.         otherAnimator.playableGraph.Evaluate(time);
    10.     rigBuilder.Evaluate(time);
    11. }
    All graphs are set to manual mode and the RigBuilder is disabled.

    Without Manual Evaluation:
    Link



    With Manual Evaluation:
    Link

     
  5. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    Evaluating the nested AnimatorController PlayableGraph in the Animator will not work well. It is accessible, but it shouldn't be evaluated directly and its update time should not be modified like that.

    In order to make your example work, you're probably disabling the Animator to avoid having it evaluate automatically. This will prevent your custom PlayableGraph from evaluating.

    Instead, you can create the PlayableGraph yourself with an `AnimatorControllerPlayable` node to evaluate your state machine. By keeping the Animator enabled with no state machine, you'll be able to control how your PlayableGraph evaluate manually.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Animations;
    3. using UnityEngine.Animations.Rigging;
    4. using UnityEngine.Playables;
    5.  
    6. [RequireComponent(typeof(Animator))]
    7. [RequireComponent(typeof(RigBuilder))]
    8. public class ManualEval : MonoBehaviour
    9. {
    10.     public RuntimeAnimatorController controller;
    11.    
    12.     private Animator m_Animator;
    13.     private RigBuilder m_RigBuilder;
    14.  
    15.     private PlayableGraph m_ControllerGraph;
    16.    
    17.     void OnEnable()
    18.     {
    19.         m_Animator = GetComponent<Animator>();
    20.         m_RigBuilder = GetComponent<RigBuilder>();
    21.  
    22.         if (controller != null)
    23.         {
    24.             m_ControllerGraph = PlayableGraph.Create();
    25.             m_ControllerGraph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
    26.            
    27.             var controllerPlayable = AnimatorControllerPlayable.Create(m_ControllerGraph, controller);
    28.             var output = AnimationPlayableOutput.Create(m_ControllerGraph, "output", m_Animator);
    29.             output.SetSourcePlayable(controllerPlayable);
    30.         }
    31.  
    32.         // Disable the RigBuilder and set its PlayableGraph to manual update mode
    33.         // to let the script evaluate it instead.
    34.         m_RigBuilder.enabled = false;
    35.         if (m_RigBuilder.Build())
    36.         {
    37.             m_RigBuilder.graph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
    38.         }
    39.     }
    40.  
    41.     private void OnDisable()
    42.     {
    43.         if (m_ControllerGraph.IsValid())
    44.             m_ControllerGraph.Destroy();
    45.     }
    46.  
    47.     // Update is called once per frame
    48.     void Update()
    49.     {
    50.         if (m_ControllerGraph.IsValid())
    51.             m_ControllerGraph.Evaluate(Time.deltaTime);
    52.         m_RigBuilder.Evaluate(Time.deltaTime);
    53.     }
    54. }
    55.  
     
    Lorrak likes this.
  6. rile-s

    rile-s

    Joined:
    Sep 18, 2019
    Posts:
    26
    As much as I wish it weren't true, creating a new playable graph doesn't work either. I've modified my code and used the example you provided in a new blank project. But, the same issue persists. The new project was made in Unity 2021.3.5f1 and I used version 1.2.0 of the package.

    Just in case I have also included more footage of the issue.
    (The footage was recorded using the example code)
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
  8. rile-s

    rile-s

    Joined:
    Sep 18, 2019
    Posts:
    26
    Thanks for the tip Kybernetic!
    Putting everything into one graph solved the problem.

    Here is exactly what I did for those who stumble upon this problem.
    A playable graph is created and I create two outputs, one for the main animator, and another for the subset of animations. The main is assigned to it's runtime controller, while the subset is left open for other animations set at runtime.

    Thanks again, Simon and Kybernetic!

    Code:
    Code (CSharp):
    1.     private void OnEnable() {
    2.         playableGraph = PlayableGraph.Create(gameObject.name + ".HumanAnim");
    3.         playableGraph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
    4.  
    5.         // Create main playable
    6.         var mainPlayable = AnimatorControllerPlayable.Create(playableGraph, mainController);
    7.         var mainOutput = AnimationPlayableOutput.Create(playableGraph, "MainOutput", mainAnimator);
    8.         mainOutput.SetSourcePlayable(mainPlayable);
    9.      
    10.         // Create subset playable
    11.         subsetOutput = AnimationPlayableOutput.Create(playableGraph, "SubsetOutput", otherAnimator);
    12.  
    13.         // Add rigs
    14.         rigBuilder.Build(playableGraph);
    15.  
    16.         FPSProxy.OnUpdate += UpdateFPS;
    17.     }
    18.  
    19.     private void OnDisable() {
    20.         FPSProxy.OnUpdate -= UpdateFPS;
    21.  
    22.         if (playableGraph.IsValid()) playableGraph.Destroy();
    23.     }
    24.  
    25.     private void UpdateFPS(float time) {
    26.         playableGraph.Evaluate(time);
    27.         rigBuilder.SyncLayers();
    28.     }
    29.  
    FYI: The RigBuilder is disabled, its just not in this snippet.
     
  9. ferrous

    ferrous

    Joined:
    Dec 31, 2012
    Posts:
    17
    I'm trying something somewhat similar, in that I've got a lot of expensive Animators, and I'd like to only run a few of them every frame. I'd like to do this with playablegraphs, but haven't had any success. I've tried both rile-s's and simonbz 's snippets above, but it most definitely needs an Animator to not be disabled, and those Animators are definitely running at full tilt when enabled, as my framerate tanks as the number of Animators goes up even if I'm only calling Evaluate a few times a frame, and have all my UpdateModes set to manual. And in profiler, it's all DirectorUpdateAnimationBegin/End that's killing me.

    Is there a step I'm I'm missing to ensure the Animator doesn't run? If I disable it, I get Tpose.
     
    PanoTron likes this.
  10. Deceleris

    Deceleris

    Joined:
    Jan 3, 2018
    Posts:
    22
    Why they didn't have designed the rig system to be ticked either manually or when the animator is updated ? Now I have to lose a whole day trying to make an obvious thing work
     
    Kasperrr likes this.