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 have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

AssetPostProcessor - Mecanim...

Discussion in 'Scripting' started by lordofduct, Dec 27, 2014.

  1. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I can't figure out how to set animation settings for Mecanim animations in AssetPostProcessor.

    On either OnPreprocessModel or OnPostProcessModel, the ModelImporter.clipAnimations does not contain any entries.

    During OnPostProcessModel, AnimationUtility.GetAnimationClips does not return anything.

    Googling around I found some people using 'Object.FindObjectsOfType<AnimationClip>()'. But two issues arise.
    1) it often returns more animations than are being processed currently (to be expected really if you think about it)
    2) If I get the 'AnimationClipSettings' from it, it doesn't actually update the settings as I want them... nor do I know what setting to change to make it 'Bake Into Pose'.



    Here's what I need really. I want it so that all my models that are imported have their animations set to have all three root transforms (rotation, positionY, positionXZ) to be 'Bake Into Pose' and 'Based Upon Original'.

    Of course this is NOT the default import setting, which is really annoying, and I have far too many animations to be constantly doing this by hand for every single animation. But of course, post processing mecanim settings has little to no documentation what so ever.

    Any help would be much appreciated!
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
  3. captaingabi

    captaingabi

    Joined:
    Jan 27, 2015
    Posts:
    1
    Hi

    The only solution I have found is to manually create a ModelImporterClipAnimation[], fill it up with data and assign it to clipAnimations. Note that even after model is imported once, you cannot modify clipAnimations elements from an editor script. To get the data you can either use an FBX parser or use the data Unity already parsed in importedTakeInfos variable. importedTakeInfos is a NonPublic Property which can be accessed by Reflection. Credits to AlkisFortuneFish for this nice solution.

    More details:
    http://forum.unity3d.com/threads/editor-script-for-editing-animation-settings-after-import.166239/

    Alternatively there are 2 interesting release notes for Unity 5.0:
    http://unity3d.com/unity/beta/5.0/release-notes
    • Added AssetPostProcessor.OnPreProcessAnimation, this new callback is called just before animation clips are created.
    • Added ModelImporter.defaultClipAnimations (list of ModelImportClipAnimation based on TakeInfo) and ModelImporter.importedTakeInfos (list of TakeInfo from the file).
    • Added API for Avatar

    BTW you still need to assign avatar rig for every animation manually, I did not found a way around that in Unity 4.x so far.

    Here is my Editor script I use with Unity 4.x, customize to your liking...

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Reflection;
    5.  
    6. public class CustomImportSettings : AssetPostprocessor
    7. {
    8.     void OnPreprocessModel()
    9.     {
    10.         ModelImporter importer = assetImporter as ModelImporter;
    11.         importer.importMaterials = false;
    12.     }
    13.  
    14.     public void OnPostprocessModel(GameObject obj)
    15.     {
    16.         ModelImporter modelImporter = (ModelImporter) assetImporter;
    17.  
    18.         if(modelImporter.assetPath.Contains("@")) { /*For animations*/
    19.             PropertyInfo prop = typeof(ModelImporter).GetProperty("importedTakeInfos", BindingFlags.NonPublic | BindingFlags.Instance);
    20.             TakeInfo[] ti = (TakeInfo[]) prop.GetValue(modelImporter, null);
    21.             if(modelImporter.clipAnimations.Length == 0) modelImporter.clipAnimations = SetupDefaultClips(ti);
    22.         } else { /*For models*/
    23.             modelImporter.importAnimation = false;
    24.         }
    25.     }
    26.  
    27.     ModelImporterClipAnimation[] SetupDefaultClips (TakeInfo[] importedTakeInfos)
    28.     {
    29.         ModelImporterClipAnimation[] clips = new ModelImporterClipAnimation[importedTakeInfos.Length];
    30.         for (int i = 0; i < importedTakeInfos.Length; i++) {
    31.             TakeInfo takeInfo = importedTakeInfos [i];
    32.             ModelImporterClipAnimation mica = new ModelImporterClipAnimation ();
    33.             mica.name = takeInfo.defaultClipName;
    34.             mica.takeName = takeInfo.name;
    35.             mica.firstFrame = (float)((int)Mathf.Round (takeInfo.bakeStartTime * takeInfo.sampleRate));
    36.             mica.lastFrame = (float)((int)Mathf.Round (takeInfo.bakeStopTime * takeInfo.sampleRate));
    37.             mica.maskType = ClipAnimationMaskType.CreateFromThisModel;
    38.             mica.keepOriginalPositionY = true;
    39.             mica.keepOriginalPositionXZ = true;
    40.             mica.keepOriginalOrientation = true;
    41.             mica.lockRootHeightY = true;
    42.             mica.lockRootPositionXZ = true;
    43.             mica.lockRootRotation = true;
    44.             clips [i] = mica;
    45.         }
    46.  
    47.         return clips;
    48.     }
    49. }
    50.  
     
    Last edited: Jan 28, 2015
  4. Zyxil

    Zyxil

    Joined:
    Nov 23, 2009
    Posts:
    111
    Here is my version of this in Unity 5.6. Much easier now:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. public class BakeXZSetterPostProcessor : AssetPostprocessor
    7. {
    8.     private static readonly string[] keywords = new string[]
    9.     {
    10.         "Attack",
    11.         "Idle",
    12.         "Death1",
    13.         "Revive1",
    14.         "Block",
    15.         "GetHit"
    16.     };
    17.  
    18.     public void OnPostprocessModel(GameObject root)
    19.     {
    20.  
    21.         // Modify ModelImporter meta data and reimport the asset
    22.         ModelImporter modelImporter = assetImporter as ModelImporter;
    23.  
    24.         if(root.name.Contains("RPG-Character@"))
    25.         {
    26.             foreach(string kwd in keywords)
    27.                 if(root.name.Contains(kwd))
    28.                 {
    29.                     ModelImporterClipAnimation[] clipAnimations = modelImporter.clipAnimations;
    30.  
    31.                     foreach(ModelImporterClipAnimation clip in clipAnimations)
    32.                         if(!clip.lockRootPositionXZ)
    33.                         {
    34.                             Debug.Log("Locking root motion XZ on RPG animation, clip : " + root.name);
    35.  
    36.                             clip.lockRootPositionXZ = true;
    37.                         }
    38.  
    39.                     modelImporter.clipAnimations = clipAnimations;
    40.                 }
    41.         }
    42.  
    43.     }
    44. }
    45.  
    46.  
     
  5. GamerYulei

    GamerYulei

    Joined:
    Nov 30, 2016
    Posts:
    1
    thanks Zyxil, it works well, only a small problem, every time after postprocess, the gameobject in editor become unapplied and popup a dialog, i have to manual click apply, do you have same issue?
     
  6. tealm

    tealm

    Joined:
    Feb 4, 2014
    Posts:
    108
    Last edited: Feb 1, 2021