Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here:
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice
  4. Join us on Thursday, September 29, for a day with Unity's SRP teams here on the forum or on Reddit, and discuss topics around URP, HDRP, and the Scriptable Render Pipeline in general.
    Dismiss Notice

Bug playable graph with 2 outputs not working

Discussion in 'Animation' started by JeremyJQ, Aug 13, 2021.

  1. JeremyJQ


    Aug 13, 2021
    We have this script to build a playable graph.

    There are two input animation clips: FullBodyClip with all bones in the skeleton animated; UpperBodyClip is from the same FBX file, but with an upper body mask, so only the bones in the upper body are animated.

    If BaseLayerUseFullBodyAnim is set to true, everything works fine.

    But if BaseLayerUseFullBodyAnim is set to false, and drag BlendingWeight between 0-1. The upper body animation is still correct, but lower body bone's rotations are way off (which is not same value as FullBodyClip, or avatar's default pose).

    The test is about two outputs. Output1 is connected to UpperBodyClip, with SortingOrder(10);

    OutPut2 is connected to m_mixer, with SortingOrder(10);

    m_mixer is just blending UpperBodyClip and FullBodyClip.

    Thanks a lot in advance.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Playables;
    3. using UnityEngine.Animations;
    4. using UnityEngine.Experimental.Animations;
    6. [RequireComponent(typeof(Animator))]
    7. public class TwoOutputTest : MonoBehaviour
    8. {
    9.     public AnimationClip UpperBodyClip;
    10.     public AnimationClip FullBodyClip;
    11.     public AnimationStreamSource BaseLayerStreamSource = AnimationStreamSource.DefaultValues;
    12.     public AnimationStreamSource TopLayerStreamSource = AnimationStreamSource.DefaultValues;
    13.     public bool BaseLayerUseFullBodyAnim = true;
    14.     [Range(0f, 1f)]    public float BlendingWeight;
    16.     private PlayableGraph m_playableGraph;
    17.     private AnimationMixerPlayable m_mixer;
    18.     //private AnimationLayerMixerPlayable m_layerMixer;
    20.     void Start()
    21.     {
    22.         Start2outputTest();
    23.     }
    25.     void OnDisable()
    26.     {
    27.         m_playableGraph.Destroy();
    28.     }
    30.     [ContextMenu("start2outputTest")]
    31.     void Start2outputTest()
    32.     {
    33.         m_playableGraph = PlayableGraph.Create("2outputTest");
    34.         m_playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
    35.         Animator srcAnimator = this.GetComponent<Animator>();
    37.         AnimationPlayableOutput o1 = AnimationPlayableOutput.Create(m_playableGraph, "layer0", srcAnimator);
    38.         var layer0ClipPlayable = AnimationClipPlayable.Create(m_playableGraph, BaseLayerUseFullBodyAnim? FullBodyClip: UpperBodyClip);
    39.         o1.SetSourcePlayable(layer0ClipPlayable);  
    40.         o1.SetSortingOrder(10);
    41.         o1.SetAnimationStreamSource(BaseLayerStreamSource);
    43.         AnimationClipPlayable layer1ClipPlayable0 = AnimationClipPlayable.Create(m_playableGraph, UpperBodyClip);
    44.         AnimationClipPlayable layer1ClipPlayable1 = AnimationClipPlayable.Create(m_playableGraph, FullBodyClip);
    45.         m_mixer = AnimationMixerPlayable.Create(m_playableGraph, 2);
    46.         m_playableGraph.Connect(layer1ClipPlayable0, 0, m_mixer, 0);
    47.         m_playableGraph.Connect(layer1ClipPlayable1, 0, m_mixer, 1);
    49.         AnimationPlayableOutput o2 = AnimationPlayableOutput.Create(m_playableGraph, "layer1", srcAnimator);
    50.         o2.SetSourcePlayable(m_mixer);      
    51.         o2.SetSortingOrder(20);
    52.         o2.SetAnimationStreamSource(TopLayerStreamSource);
    53.         m_playableGraph.Play();
    54.     }
    56.     void Update()
    57.     {
    58.         m_mixer.SetInputWeight(0, 1f - BlendingWeight);
    59.         m_mixer.SetInputWeight(1, BlendingWeight);
    60.     }
    61. }
  2. JeremyJQ


    Aug 13, 2021
    And we already know the workaround: instead of using two outputs, use just one output and connect it to a AnimationLayerMixerPlayable m_layerMixer , which has layer1 branch connected to UpperBodyClip; and layer2 connected to m_mixer. And it works correctly.

    But our project has some complicated playable graphs that must have multiple outputs, so we build this simplified test case to report the bug.

    Our understanding is SetSortingOrder() of two outputs will guarantee the top layer output override the base layer output’s animation. But when base layer output has FullBodyClip, everything works. If base layer output has UpperBodyClip, it somehow corrupted the animation data of top layer?
  3. DavidGeoffroy


    Unity Technologies

    Sep 9, 2014
    There are some issues with blending between outputs, which can be compounded by having clips with different sets of bones, Humanoid vs Genereic, as well as Animation masks. Some are fixable without breaking existing behaviour, some not.

    Behaviour may also vary quite a lot between Unity versions, as not all bugfixes are backported.

    Your best bet is to report this as a bug, so the Animation devs can debug with your assets and see exactly what the issue is.