Search Unity

AnimatorController.AddLayer() doesn't create default AnimatorStateMachine

Discussion in 'Animation' started by sunnydavis, Mar 6, 2015.

  1. sunnydavis

    sunnydavis

    Joined:
    Aug 2, 2010
    Posts:
    45
    When using AnimatorController.AddLayer() to add a new layer, it doesn't automatically create a root state machine for me, I must create it myself. This doesn't feel right to me, because there is no utility function to create a root state machine, and the base layer always has a root state machine ready to be used. Is this the intended behavior or a bug?
     
    tobad likes this.
  2. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Use AddLayer(string name) which add the SM for you and setup all the internal flag.

    http://docs.unity3d.com/ScriptReference/Animations.AnimatorController.AddLayer.html

    You can do it manually also if you prefer, here what AddLayer(string name) does under the cover

    Code (CSharp):
    1.  
    2. newLayer.stateMachine = new AnimatorStateMachine();
    3. newLayer.stateMachine.name = newLayer.name;
    4. newLayer.stateMachine.hideFlags = HideFlags.HideInHierarchy;
    5.  
    6. if (AssetDatabase.GetAssetPath(controller) != "")
    7.             AssetDatabase.AddObjectToAsset(newLayer.stateMachine, AssetDatabase.GetAssetPath(controller));
    8.  
     
    NGC6543 and tobad like this.
  3. sunnydavis

    sunnydavis

    Joined:
    Aug 2, 2010
    Posts:
    45
    Ah I see. Thanks!
     
  4. tobad

    tobad

    Joined:
    Mar 12, 2015
    Posts:
    90
    thank you sooo much for asking this @sunnydavis

    setting defaultWeight and AnimatorLayerBlendingMode in this way doesnt work:
    HashID.l_overlay is
    Code (CSharp):
    1. public static string l_overlay = "Special Layer";
    Code (CSharp):
    1.         // Auto Creating Layer & StateMachine  AddLayer(string)!!!
    2.         controller.AddLayer(HashID.l_overlay);
    3.         controller.layers[1].blendingMode = AnimatorLayerBlendingMode.Override;            // setzt für die zeit die es aktiv ist die variablen und wenn deaktiviert wird variable auf vorherigen wert gesetzt
    4.         controller.layers[1].defaultWeight = 1f;
    5.  
    setting defaultWeight and AnimatorLayerBlendingMode only works with manual creating a AnimatorControllerLayer and add it do the controller (AnimatorController)

    Code (CSharp):
    1.         AnimatorControllerLayer newLayer = new AnimatorControllerLayer();
    2.         newLayer.name = HashID.l_overlay;
    3.         newLayer.stateMachine = new AnimatorStateMachine();
    4.         newLayer.stateMachine.name = newLayer.name;
    5.         newLayer.stateMachine.hideFlags = HideFlags.HideInHierarchy;
    6.         if (AssetDatabase.GetAssetPath(controller) != "")
    7.             AssetDatabase.AddObjectToAsset(newLayer.stateMachine, AssetDatabase.GetAssetPath(controller));
    8.         //Custom
    9.         newLayer.blendingMode = AnimatorLayerBlendingMode.Additive;
    10.         newLayer.defaultWeight = 1f;
    11.         controller.AddLayer(newLayer);


    so thanks again for pointing that out!
     
  5. Sv7en

    Sv7en

    Joined:
    Oct 21, 2016
    Posts:
    1
    thanks it's useful!
     
  6. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    Hi @Mecanim-Dev ,
    I made a custom script that re-writes a given AnimatorController. The result is fine. But the problem is, when I re-opens the project, some data inside the AnimatorController asset are missing(Transitions, Motions, ...) Only States or State Machines remain.
    I think the problem is that the change made by the script is not saved into the disk.

    Code (CSharp):
    1. [SerializeField] AnimatorController controller;
    2. public void UpdateAnimatorController()
    3. {
    4.         /*
    5.             1. Reset all parameters.
    6.             2. Reset all layers.
    7.             3. Create "Move" layer (layer0)
    8.             4. Create "Action" layer (layer1)
    9.         */
    10.         // I added below but still have the issue.
    11.         AssetDatabase.StartAssetEditing();
    12.      
    13.         ResetParameters();
    14.      
    15.         ResetLayers();
    16.      
    17.         CreateMoveLayer();
    18.      
    19.         CreateActionLayer();
    20.      
    21.         // I added below but still have the issue.
    22.         AssetDatabase.StopAssetEditing();
    23.      
    24.         EditorUtility.SetDirty(controller);
    25.         AssetDatabase.SaveAssets();
    26.         AssetDatabase.Refresh();
    27. }
    I set the target Animator Controller 'Dirty' and then save the change by calling AssetDatabase.SaveAssets().
    What can be wrong here? Could someone give me an advice?

    ++ Above code snippet is part of my whole code.
     
  7. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    hi @NGC6543,

    it depends on how you create and add thoses objects(Transition, BlendTree) to the controller. Unfortunatelly with this code snippet I can't see how you do that, I would need to see your CreateMoveLayer() methods

    But since thoses object are assets, it does mean that you either have the choice to save them directly into the controller asset file or save them into their own asset file and reference them from the controller.

    By example for blendtree, there is two different function to add them into controller.

    https://docs.unity3d.com/ScriptReference/Animations.AnimatorController.AddMotion.html
    https://docs.unity3d.com/ScriptRefe...orController.CreateBlendTreeInController.html

    the first one expect that you are managing your self the motion asset, the motion asset in this case is not added to the controller asset file but the animator state created by this function would be.

    the second one does manage the motion asset, in this case the blend tree will be added to the controller asset file with the animator state.


    here the code for both function to show you the detail
    Code (CSharp):
    1.  
    2. public AnimatorState AddMotion(Motion motion, int layerIndex)
    3.         {
    4.             AnimatorState state = layers[layerIndex].stateMachine.AddState(motion.name);
    5.             state.motion = motion;
    6.             return state;
    7.         }
    8.  
    9.         public AnimatorState CreateBlendTreeInController(string name, out BlendTree tree, int layerIndex)
    10.         {
    11.             tree = new BlendTree();
    12.             tree.name = name;
    13.             tree.blendParameter = tree.blendParameterY = GetDefaultBlendTreeParameter();
    14.  
    15.             if (AssetDatabase.GetAssetPath(this) != "")
    16.                 AssetDatabase.AddObjectToAsset(tree, AssetDatabase.GetAssetPath(this));
    17.  
    18.             AnimatorState state = layers[layerIndex].stateMachine.AddState(tree.name);
    19.             state.motion = tree;
    20.             return state;
    21.         }
    22.  
    the important part is the call to
    Code (CSharp):
    1.  
    2. AssetDatabase.AddObjectToAsset(tree, AssetDatabase.GetAssetPath(this));
    3.  
    The documentation should have a note on each controller function to tell you if the asset is managed or not by the controller like this: "The BlendTree will be a sub asset of the AnimatorController. "

    One way to test this is to check if your asset are managed by the AssetDatabase with a call to
    AssetDatabase,GetAssetPath(), if it returns an empty string then your asset is not managed and will be lost if you close the editor.
     
  8. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    I really appreciate your kind and thorough reply.
    I didn’t think those transitions and blendtrees are separate assets on their own.
    In my code I just save root state machine for a layer by something like ‘AddObjectToAsset()’ (I’m home using my phone now). I saw another thread about adding states with ‘hideinhiararchy’ option. Now I understand what that means!

    Thanks again for your support!