Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Script to rename mixamo animations clips names automatic

Discussion in 'Assets and Asset Store' started by Chocolade, Dec 30, 2018.

  1. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    941
    After downloading mixamo fbx files and drag them to the animator controller all the names are the same mixamo.com
    With this script it's converting the names according to the files names on the hard disk.

    Can be done I think also when importing the fbx files once the editor importing them but I prefered to use the EditorWindow.

    The first screenshot the fbx downloaded files on the hard disk inside the assets under some child folders. 12 files:



    When moving to the editor it will import automatic the files:



    Next dragging the files to the animator controller all the states names are the same mixamo.com



    Now I removed the states from the controller that was just to show they are all have the same name.
    And selecting in the editor menu: Window > Mixamo Manager and click on the Rename button:

    And now when dragging again the files/or only the animations to the controller:



    The script should be in Assets/Editor folder:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Linq;
    6. using System.Reflection;
    7. using UnityEditor;
    8. using UnityEngine;
    9.  
    10. public class MixamoManager : EditorWindow
    11. {
    12.     private static MixamoManager editor;
    13.     private static int width = 350;
    14.     private static int height = 300;
    15.     private static int x = 0;
    16.     private static int y = 0;
    17.     private static List<string> allFiles = new List<string>();
    18.    
    19.     [MenuItem("Window/Mixamo Manager")]
    20.     static void ShowEditor()
    21.     {
    22.         editor = EditorWindow.GetWindow<MixamoManager>();
    23.         CenterWindow();
    24.     }
    25.  
    26.     private void OnGUI()
    27.     {
    28.         if (GUILayout.Button("Rename"))
    29.         {
    30.             Rename();
    31.         }
    32.     }
    33.    
    34.     public void Rename()
    35.     {
    36.         DirSearch();
    37.  
    38.         if (allFiles.Count > 0)
    39.         {
    40.             for (int i = 0; i < allFiles.Count; i++)
    41.             {
    42.                 int idx = allFiles[i].IndexOf("Assets");
    43.                 string filename = Path.GetFileName(allFiles[i]);
    44.                 string asset = allFiles[i].Substring(idx);
    45.                 AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    46.                     asset, typeof(AnimationClip));
    47.  
    48.                 var fileName = Path.GetFileNameWithoutExtension(allFiles[i]);
    49.                 var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    50.  
    51.                 RenameAndImport(importer, fileName);
    52.             }
    53.         }
    54.     }
    55.  
    56.     private void RenameAndImport(ModelImporter asset, string name)
    57.     {
    58.         ModelImporter modelImporter = asset as ModelImporter;
    59.         ModelImporterClipAnimation[] clipAnimations = modelImporter.defaultClipAnimations;
    60.  
    61.         for (int i = 0; i < clipAnimations.Length; i++)
    62.         {
    63.             clipAnimations[i].name = name;
    64.         }
    65.        
    66.         modelImporter.clipAnimations = clipAnimations;
    67.         modelImporter.SaveAndReimport();
    68.     }
    69.  
    70.     private static void CenterWindow()
    71.     {
    72.         editor = EditorWindow.GetWindow<MixamoManager>();
    73.         x = (Screen.currentResolution.width - width) / 2;
    74.         y = (Screen.currentResolution.height - height) / 2;
    75.         editor.position = new Rect(x, y, width, height);
    76.         editor.maxSize = new Vector2(width, height);
    77.         editor.minSize = editor.maxSize;
    78.     }
    79.  
    80.     static void DirSearch()
    81.     {
    82.         string info = Application.dataPath; //+ "/Mixamo/Animations/medea_m_arrebola/Magic";
    83.         string[] fileInfo = Directory.GetFiles(info, "*.fbx", SearchOption.AllDirectories);
    84.         foreach (string file in fileInfo)
    85.         {
    86.             if (file.EndsWith(".fbx"))
    87.                 allFiles.Add(file);
    88.         }
    89.     }
    90. }
    91.  
    In my code I'm searching for any fbx files in the Assets but you can put a specific folder for example:

    Code (csharp):
    1.  
    2. string info = Application.dataPath + /Mixamo/Animations/medea_m_arrebola/Magic";
    3.  
     
  2. MatrixWeaver

    MatrixWeaver

    Joined:
    Sep 22, 2016
    Posts:
    3
    Thank you so much for this!
     
  3. unity_nV9rCDWvloHkDA

    unity_nV9rCDWvloHkDA

    Joined:
    Feb 1, 2018
    Posts:
    1
    Thanks, this is very helpful.
     
  4. pointcache

    pointcache

    Joined:
    Sep 22, 2012
    Posts:
    579


    Changed the script a bit
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Linq;
    6. using System.Reflection;
    7. using UnityEditor;
    8. using UnityEngine;
    9.  
    10. public class AnimImporterTool : EditorWindow
    11. {
    12.     private static AnimImporterTool editor;
    13.     private static int width =300;
    14.     private static int height = 500;
    15.     private static int x = 0;
    16.     private static int y = 0;
    17.     private static List<string> allFiles = new List<string>();
    18.  
    19.     private static Settings settings = new Settings();
    20.     private const string settings_prefs_path = nameof(AnimImporterTool) + "_lastsettings";
    21.     private static Color linecolor = new Color32(128, 128, 128, 64);
    22.     [System.Serializable]
    23.     private class Settings
    24.     {
    25.         public string path = string.Empty;
    26.         public bool rename_anim_clips = true;
    27.         public bool rename_anim_clips_underscores = true;
    28.         public bool rename_anim_clips_tolower = true;
    29.         public bool change_loop_anim_clips = true;
    30.         public bool loop_anim_clips_time = true;
    31.         public bool loop_anim_clips_pose = false;
    32.         public bool root_transform_rotation = false;
    33.         public bool root_transform_rotation_bakeintopose = false;
    34.         public bool root_transform_rotation_keep_original = false;
    35.         public float root_transform_rotation_offset = 0f;
    36.  
    37.         public bool disable_material_import = true;
    38.         public bool mirror = false;
    39.         public bool set_rig_to_humanoid = true;
    40.         public Avatar rig_custom_avatar;
    41.     }
    42.  
    43.     [MenuItem("pFramework/AnimImporterTool")]
    44.     static void ShowEditor()
    45.     {
    46.         editor = EditorWindow.GetWindow<AnimImporterTool>();
    47.         CenterWindow();
    48.         LoadSettings();
    49.     }
    50.  
    51.     private void OnGUI()
    52.     {
    53.  
    54.             EditorGUILayout.BeginHorizontal();
    55.         if (GUILayout.Button("Select directory"))
    56.         {
    57.             settings.path = EditorUtility.OpenFolderPanel("Select directory with files", "", "");
    58.         }
    59.         if (GUILayout.Button("Reset settings"))
    60.         {
    61.             settings = new Settings();
    62.         }
    63.  
    64.         if (GUILayout.Button("Save settings"))
    65.         {
    66.             SaveSettings();
    67.         }
    68.         EditorGUILayout.EndHorizontal();
    69.  
    70.         GUILayout.Label($"Path: {settings.path} ", EditorStyles.boldLabel);
    71.         GUILayout.Label($"Selected: {Selection.gameObjects.Length} assets", EditorStyles.boldLabel);
    72.  
    73.         bool pathvalid = !string.IsNullOrEmpty(settings.path) && Directory.Exists(settings.path);
    74.         if (!pathvalid)
    75.         {
    76.             GUI.color = Color.red;
    77.             GUILayout.Label("Path invalid", EditorStyles.boldLabel);
    78.             GUI.color = Color.white;
    79.         }
    80.  
    81.         DrawUILine();
    82.         settings.rename_anim_clips = EditorGUILayout.BeginToggleGroup("Rename anim clips to filename", settings.rename_anim_clips);
    83.         {
    84.             settings.rename_anim_clips_underscores = EditorGUILayout.Toggle("Spaces to underscores", settings.rename_anim_clips_underscores);
    85.             settings.rename_anim_clips_tolower = EditorGUILayout.Toggle("To lower", settings.rename_anim_clips_tolower);
    86.         }
    87.         EditorGUILayout.EndToggleGroup();
    88.         GUILayout.Space(5);
    89.  
    90.         DrawUILine();
    91.         settings.change_loop_anim_clips = EditorGUILayout.BeginToggleGroup("Change looping", settings.change_loop_anim_clips);
    92.         {
    93.             settings.loop_anim_clips_time = EditorGUILayout.Toggle("Loop time", settings.loop_anim_clips_time);
    94.             settings.loop_anim_clips_pose = EditorGUILayout.Toggle("Loop pose", settings.loop_anim_clips_pose);
    95.         }
    96.         EditorGUILayout.EndToggleGroup();
    97.         GUILayout.Space(5);
    98.  
    99.         DrawUILine();
    100.         settings.root_transform_rotation = EditorGUILayout.BeginToggleGroup("Root transform rotation", settings.root_transform_rotation);
    101.         {
    102.             settings.root_transform_rotation_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_rotation_bakeintopose);
    103.             settings.root_transform_rotation_keep_original = EditorGUILayout.Toggle("Keep original", settings.root_transform_rotation_keep_original);
    104.             settings.root_transform_rotation_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_rotation_offset);
    105.         }
    106.         EditorGUILayout.EndToggleGroup();
    107.         GUILayout.Space(5);
    108.  
    109.         GUILayout.Label("Misc", EditorStyles.boldLabel);
    110.         DrawUILine();
    111.         settings.set_rig_to_humanoid = EditorGUILayout.Toggle("Set rig to humanoid", settings.set_rig_to_humanoid);
    112.         settings.disable_material_import = EditorGUILayout.Toggle("Disable material import", settings.disable_material_import);
    113.         settings.mirror = EditorGUILayout.Toggle("Mirror", settings.mirror);
    114.         settings.rig_custom_avatar = EditorGUILayout.ObjectField("Custom avatar", settings.rig_custom_avatar, typeof(Avatar), false) as Avatar;
    115.  
    116.         GUILayout.Space(30);
    117.         DrawUILine();
    118.         GUILayout.BeginHorizontal();
    119.  
    120.         GUI.enabled = pathvalid;
    121.         if (GUILayout.Button("Process directory"))
    122.         {
    123.             process_dir();
    124.             SaveSettings();
    125.         }
    126.         GUI.enabled = Selection.gameObjects.Length > 0;
    127.         if (GUILayout.Button("Process selected assets"))
    128.         {
    129.             processSelectedAssets();
    130.             SaveSettings();
    131.         }
    132.         GUI.enabled = true;
    133.         GUILayout.EndHorizontal();
    134.  
    135.     }
    136.  
    137.     private static void SaveSettings()
    138.     {
    139.         string json = EditorJsonUtility.ToJson(settings);
    140.         EditorPrefs.SetString(settings_prefs_path, json);
    141.     }
    142.  
    143.     private static void LoadSettings()
    144.     {
    145.         settings = JsonUtility.FromJson<Settings>(EditorPrefs.GetString(settings_prefs_path));
    146.         if (settings == null)
    147.             settings = new Settings();
    148.     }
    149.  
    150.     public void process_dir()
    151.     {
    152.         DirSearch(settings.path);
    153.  
    154.         if (allFiles.Count > 0)
    155.         {
    156.             for (int i = 0; i < allFiles.Count; i++)
    157.             {
    158.                 int idx = allFiles[i].IndexOf("Assets");
    159.                 string filename = Path.GetFileName(allFiles[i]);
    160.                 string asset = allFiles[i].Substring(idx);
    161.                 AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    162.                     asset, typeof(AnimationClip));
    163.  
    164.                 var fileName = Path.GetFileNameWithoutExtension(allFiles[i]);
    165.                 var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    166.  
    167.                 EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", filename, (1f / allFiles.Count) * i);
    168.  
    169.                 RenameAndImport(importer, fileName);
    170.             }
    171.         }
    172.  
    173.         EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", "Saving assets", 1f);
    174.         AssetDatabase.SaveAssets();
    175.         EditorUtility.ClearProgressBar();
    176.  
    177.     }
    178.  
    179.     public void processSelectedAssets()
    180.     {
    181.         int count = Selection.gameObjects.Length;
    182.         if (count > 0)
    183.         {
    184.             for (int i = 0; i < count; i++)
    185.             {
    186.                 UnityEngine.Object asset = Selection.gameObjects[i];
    187.                 string assetpath = AssetDatabase.GetAssetPath(asset);
    188.                 AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    189.                     assetpath, typeof(AnimationClip));
    190.  
    191.                 var fileName = asset.name;
    192.                 var importer = (ModelImporter)AssetImporter.GetAtPath(assetpath);
    193.  
    194.                 EditorUtility.DisplayProgressBar($"Processing {count} files", fileName, (1f / count) * i);
    195.  
    196.                 RenameAndImport(importer, fileName);
    197.             }
    198.         }
    199.  
    200.         EditorUtility.ClearProgressBar();
    201.  
    202.     }
    203.  
    204.     private void RenameAndImport(ModelImporter asset, string name)
    205.     {
    206.         ModelImporter modelImporter = asset as ModelImporter;
    207.         ModelImporterClipAnimation[] clipAnimations = modelImporter.defaultClipAnimations;
    208.  
    209.         if (settings.disable_material_import)
    210.             modelImporter.materialImportMode = ModelImporterMaterialImportMode.None;
    211.  
    212.         if (settings.set_rig_to_humanoid)
    213.             modelImporter.animationType = ModelImporterAnimationType.Human;
    214.  
    215.         if (settings.rig_custom_avatar != null)
    216.             modelImporter.sourceAvatar = settings.rig_custom_avatar;
    217.  
    218.             if (settings.rename_anim_clips_underscores)
    219.             name = name.Replace(' ', '_');
    220.  
    221.         if (settings.rename_anim_clips_tolower)
    222.             name = name.ToLower();
    223.  
    224.         for (int i = 0; i < clipAnimations.Length; i++)
    225.         {
    226.             var clip = clipAnimations[i];
    227.  
    228.             if (settings.rename_anim_clips)
    229.                 clip.name = name;
    230.             if (settings.change_loop_anim_clips)
    231.             {
    232.                 clip.loopTime = settings.loop_anim_clips_time;
    233.                 clip.loopPose = settings.loop_anim_clips_pose;
    234.                 if (settings.root_transform_rotation)
    235.                 {
    236.                     clip.lockRootRotation = settings.root_transform_rotation_bakeintopose;
    237.                     clip.keepOriginalOrientation = settings.root_transform_rotation_keep_original;
    238.                     clip.rotationOffset = settings.root_transform_rotation_offset;
    239.                 }
    240.  
    241.                    
    242.             }
    243.         }
    244.  
    245.         modelImporter.clipAnimations = clipAnimations;
    246.         modelImporter.SaveAndReimport();
    247.     }
    248.  
    249.     private static void CenterWindow()
    250.     {
    251.         editor = EditorWindow.GetWindow<AnimImporterTool>();
    252.         x = (Screen.currentResolution.width - width) / 2;
    253.         y = (Screen.currentResolution.height - height) / 2;
    254.         editor.position = new Rect(x, y, width, height);
    255.         editor.maxSize = new Vector2(width, height);
    256.         editor.minSize = editor.maxSize;
    257.     }
    258.  
    259.     static void DirSearch(string path)
    260.     {
    261.         string[] fileInfo = Directory.GetFiles(path, "*.fbx", SearchOption.AllDirectories);
    262.         foreach (string file in fileInfo)
    263.         {
    264.             if (file.EndsWith(".fbx"))
    265.                 allFiles.Add(file);
    266.         }
    267.     }
    268.  
    269.     private static void DrawUILine(int thickness = 1, int padding = 5)
    270.     {
    271.         Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
    272.         r.height = thickness;
    273.         r.y += padding / 2;
    274.         r.x -= 2;
    275.         r.width += 6;
    276.         EditorGUI.DrawRect(r, linecolor);
    277.     }
    278. }
     
  5. Forberg

    Forberg

    Joined:
    Oct 27, 2018
    Posts:
    26
    Thanks guys, exactly what I was looking for!

    Just in case anyone else needs this in the future, I added:
    • Loop Keywords: Comma or white-space separated list as input. Only sets animations to looping if their name contains one of the specified keywords (such as "run" or "walk")
    • Name Prefix: Adds a prefix to all processed animations
    • Root Motion Settings for Y and XZ

    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Linq;
    5. using UnityEditor;
    6. using UnityEngine;
    7. public class MixamoImportTool : EditorWindow
    8. {
    9.     private static MixamoImportTool editor;
    10.     private static int width = 300;
    11.     private static int height = 500;
    12.     private static int x = 0;
    13.     private static int y = 0;
    14.     private static List<string> allFiles = new List<string>();
    15.     private static Settings settings = new Settings();
    16.     private const string settings_prefs_path = nameof(MixamoImportTool) + "_lastsettings";
    17.     private static Color linecolor = new Color32(128, 128, 128, 64);
    18.     [System.Serializable]
    19.     private class Settings
    20.     {
    21.         public string path = string.Empty;
    22.         public bool rename_anim_clips = true;
    23.         public bool rename_anim_clips_underscores = true;
    24.         public bool rename_anim_clips_tolower = true;
    25.         public string rename_prefix;
    26.         public bool change_loop_anim_clips = true;
    27.         public bool loop_anim_clips_time = true;
    28.         public bool loop_anim_clips_pose = false;
    29.         public bool root_transform_rotation = false;
    30.         public bool root_transform_rotation_bakeintopose = false;
    31.         public bool root_transform_rotation_keep_original = false;
    32.         public float root_transform_rotation_offset = 0f;
    33.         public bool disable_material_import = true;
    34.         public bool mirror = false;
    35.         public bool set_rig_to_humanoid = true;
    36.         public Avatar rig_custom_avatar;
    37.         public bool root_transform_y;
    38.         public bool root_transform_y_bakeintopose;
    39.         public bool root_transform_y_keep_original;
    40.         public float root_transform_y_offset;
    41.         public bool root_transform_xz;
    42.         public bool root_transform_xz_bakeintopose;
    43.         public bool root_transform_xz_keep_original;
    44.         internal string loop_keywords;
    45.     }
    46.     [MenuItem("Window/Animation/Mixamo Import Tool")]
    47.     static void ShowEditor()
    48.     {
    49.         editor = EditorWindow.GetWindow<MixamoImportTool>();
    50.         CenterWindow();
    51.         LoadSettings();
    52.     }
    53.     private void OnGUI()
    54.     {
    55.         EditorGUILayout.BeginHorizontal();
    56.         if (GUILayout.Button("Select directory"))
    57.         {
    58.             settings.path = EditorUtility.OpenFolderPanel("Select directory with files", "", "");
    59.         }
    60.         if (GUILayout.Button("Reset settings"))
    61.         {
    62.             settings = new Settings();
    63.         }
    64.         if (GUILayout.Button("Save settings"))
    65.         {
    66.             SaveSettings();
    67.         }
    68.         EditorGUILayout.EndHorizontal();
    69.         GUILayout.Label($"Path: {settings.path} ", EditorStyles.boldLabel);
    70.         GUILayout.Label($"Selected: {Selection.gameObjects.Length} assets", EditorStyles.boldLabel);
    71.         bool pathvalid = !string.IsNullOrEmpty(settings.path) && Directory.Exists(settings.path);
    72.         if (!pathvalid)
    73.         {
    74.             GUI.color = Color.red;
    75.             GUILayout.Label("Path invalid", EditorStyles.boldLabel);
    76.             GUI.color = Color.white;
    77.         }
    78.         DrawUILine();
    79.         settings.rename_anim_clips = EditorGUILayout.BeginToggleGroup("Rename anim clips to filename", settings.rename_anim_clips);
    80.         {
    81.             settings.rename_prefix = EditorGUILayout.TextField("Prefix", settings.rename_prefix);
    82.             settings.rename_anim_clips_underscores = EditorGUILayout.Toggle("Spaces to underscores", settings.rename_anim_clips_underscores);
    83.             settings.rename_anim_clips_tolower = EditorGUILayout.Toggle("To lower", settings.rename_anim_clips_tolower);
    84.         }
    85.         EditorGUILayout.EndToggleGroup();
    86.         GUILayout.Space(5);
    87.         DrawUILine();
    88.         settings.change_loop_anim_clips = EditorGUILayout.BeginToggleGroup("Change looping", settings.change_loop_anim_clips);
    89.         {
    90.             settings.loop_keywords = EditorGUILayout.TextField("Keywords", settings.loop_keywords);
    91.             settings.loop_anim_clips_time = EditorGUILayout.Toggle("Loop time", settings.loop_anim_clips_time);
    92.             settings.loop_anim_clips_pose = EditorGUILayout.Toggle("Loop pose", settings.loop_anim_clips_pose);
    93.         }
    94.         EditorGUILayout.EndToggleGroup();
    95.         GUILayout.Space(5);
    96.         DrawUILine();
    97.         settings.root_transform_rotation = EditorGUILayout.BeginToggleGroup("Root transform rotation", settings.root_transform_rotation);
    98.         {
    99.             settings.root_transform_rotation_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_rotation_bakeintopose);
    100.             settings.root_transform_rotation_keep_original = EditorGUILayout.Toggle("Keep original", settings.root_transform_rotation_keep_original);
    101.             settings.root_transform_rotation_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_rotation_offset);
    102.         }
    103.         EditorGUILayout.EndToggleGroup();
    104.         GUILayout.Space(5);
    105.         settings.root_transform_y = EditorGUILayout.BeginToggleGroup("Root transform Y", settings.root_transform_y);
    106.         {
    107.             settings.root_transform_y_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_y_bakeintopose);
    108.             settings.root_transform_y_keep_original = EditorGUILayout.Toggle("Keep original", settings.root_transform_y_keep_original);
    109.             settings.root_transform_y_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_y_offset);
    110.         }
    111.         EditorGUILayout.EndToggleGroup();
    112.         GUILayout.Space(5);
    113.         settings.root_transform_xz = EditorGUILayout.BeginToggleGroup("Root transform XZ", settings.root_transform_xz);
    114.         {
    115.             settings.root_transform_xz_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_xz_bakeintopose);
    116.             settings.root_transform_xz_keep_original = EditorGUILayout.Toggle("Keep original", settings.root_transform_xz_keep_original);
    117.         }
    118.         EditorGUILayout.EndToggleGroup();
    119.         GUILayout.Space(5);
    120.         GUILayout.Label("Misc", EditorStyles.boldLabel);
    121.         DrawUILine();
    122.         settings.set_rig_to_humanoid = EditorGUILayout.Toggle("Set rig to humanoid", settings.set_rig_to_humanoid);
    123.         settings.disable_material_import = EditorGUILayout.Toggle("Disable material import", settings.disable_material_import);
    124.         settings.mirror = EditorGUILayout.Toggle("Mirror", settings.mirror);
    125.         settings.rig_custom_avatar = EditorGUILayout.ObjectField("Custom avatar", settings.rig_custom_avatar, typeof(Avatar), false) as Avatar;
    126.         GUILayout.Space(30);
    127.         DrawUILine();
    128.         GUILayout.BeginHorizontal();
    129.         GUI.enabled = pathvalid;
    130.         if (GUILayout.Button("Process directory"))
    131.         {
    132.             process_dir();
    133.             SaveSettings();
    134.         }
    135.         GUI.enabled = Selection.gameObjects.Length > 0;
    136.         if (GUILayout.Button("Process selected assets"))
    137.         {
    138.             processSelectedAssets();
    139.             SaveSettings();
    140.         }
    141.         GUI.enabled = true;
    142.         GUILayout.EndHorizontal();
    143.     }
    144.     private static void SaveSettings()
    145.     {
    146.         string json = EditorJsonUtility.ToJson(settings);
    147.         EditorPrefs.SetString(settings_prefs_path, json);
    148.     }
    149.     private static void LoadSettings()
    150.     {
    151.         settings = JsonUtility.FromJson<Settings>(EditorPrefs.GetString(settings_prefs_path));
    152.         if (settings == null)
    153.             settings = new Settings();
    154.     }
    155.     public void process_dir()
    156.     {
    157.         DirSearch(settings.path);
    158.         if (allFiles.Count > 0)
    159.         {
    160.             for (int i = 0; i < allFiles.Count; i++)
    161.             {
    162.                 int idx = allFiles.IndexOf("Assets");
    163.                 string filename = Path.GetFileName(allFiles);
    164.                 string asset = allFiles.Substring(idx);
    165.                 AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    166.                     asset, typeof(AnimationClip));
    167.                 var fileName = Path.GetFileNameWithoutExtension(allFiles);
    168.                 var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    169.                 EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", filename, (1f / allFiles.Count) * i);
    170.                 RenameAndImport(importer, fileName);
    171.             }
    172.         }
    173.         EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", "Saving assets", 1f);
    174.         AssetDatabase.SaveAssets();
    175.         EditorUtility.ClearProgressBar();
    176.     }
    177.     public void processSelectedAssets()
    178.     {
    179.         int count = Selection.gameObjects.Length;
    180.         if (count > 0)
    181.         {
    182.             for (int i = 0; i < count; i++)
    183.             {
    184.                 UnityEngine.Object asset = Selection.gameObjects;
    185.                 string assetpath = AssetDatabase.GetAssetPath(asset);
    186.                 AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    187.                     assetpath, typeof(AnimationClip));
    188.                 var fileName = asset.name;
    189.                 var importer = (ModelImporter)AssetImporter.GetAtPath(assetpath);
    190.                 EditorUtility.DisplayProgressBar($"Processing {count} files", fileName, (1f / count) * i);
    191.                 RenameAndImport(importer, fileName);
    192.             }
    193.         }
    194.         EditorUtility.ClearProgressBar();
    195.     }
    196.     private void RenameAndImport(ModelImporter asset, string name)
    197.     {
    198.         ModelImporter modelImporter = asset as ModelImporter;
    199.         ModelImporterClipAnimation[] clipAnimations = modelImporter.defaultClipAnimations;
    200.         if (settings.disable_material_import)
    201.             modelImporter.materialImportMode = ModelImporterMaterialImportMode.None;
    202.         if (settings.set_rig_to_humanoid)
    203.             modelImporter.animationType = ModelImporterAnimationType.Human;
    204.         if (settings.rig_custom_avatar != null)
    205.             modelImporter.sourceAvatar = settings.rig_custom_avatar;
    206.         if (settings.rename_anim_clips_underscores)
    207.             name = name.Replace(' ', '_');
    208.         if (settings.rename_anim_clips_tolower)
    209.             name = name.ToLower();
    210.         if(!string.IsNullOrEmpty(settings.rename_prefix))
    211.             name = settings.rename_prefix + name;
    212.         for (int i = 0; i < clipAnimations.Length; i++)
    213.         {
    214.             var clip = clipAnimations;
    215.             if (settings.rename_anim_clips)
    216.                 clip.name = name;
    217.             if (settings.change_loop_anim_clips)
    218.             {
    219.                 string[] keywords = settings.loop_keywords.Split(new char[] { ' ', ',', ';'}, System.StringSplitOptions.RemoveEmptyEntries);
    220.                 bool loop = keywords.Length == 0 || keywords.Any(k => name.Contains(k));
    221.                 clip.loopTime = loop && settings.loop_anim_clips_time;
    222.                 clip.loopPose = loop && settings.loop_anim_clips_pose;
    223.             }
    224.             if (settings.root_transform_rotation)
    225.             {
    226.                 clip.lockRootRotation = settings.root_transform_rotation_bakeintopose;
    227.                 clip.keepOriginalOrientation = settings.root_transform_rotation_keep_original;
    228.                 clip.rotationOffset = settings.root_transform_rotation_offset;
    229.             }
    230.             if (settings.root_transform_y)
    231.             {
    232.                 clip.lockRootHeightY = settings.root_transform_y_bakeintopose;
    233.                 clip.keepOriginalPositionY = settings.root_transform_y_keep_original;
    234.                 clip.heightOffset = settings.root_transform_y_offset;
    235.             }
    236.             if (settings.root_transform_xz)
    237.             {
    238.                 clip.lockRootPositionXZ = settings.root_transform_xz_bakeintopose;
    239.                 clip.keepOriginalPositionXZ = settings.root_transform_xz_keep_original;
    240.             }
    241.         }
    242.         modelImporter.clipAnimations = clipAnimations;
    243.         modelImporter.SaveAndReimport();
    244.     }
    245.     private static void CenterWindow()
    246.     {
    247.         editor = EditorWindow.GetWindow<MixamoImportTool>();
    248.         x = (Screen.currentResolution.width - width) / 2;
    249.         y = (Screen.currentResolution.height - height) / 2;
    250.         editor.position = new Rect(x, y, width, height);
    251.         editor.maxSize = new Vector2(width, height);
    252.         editor.minSize = editor.maxSize;
    253.     }
    254.     static void DirSearch(string path)
    255.     {
    256.         string[] fileInfo = Directory.GetFiles(path, "*.fbx", SearchOption.AllDirectories);
    257.         foreach (string file in fileInfo)
    258.         {
    259.             if (file.EndsWith(".fbx"))
    260.                 allFiles.Add(file);
    261.         }
    262.     }
    263.     private static void DrawUILine(int thickness = 1, int padding = 5)
    264.     {
    265.         Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
    266.         r.height = thickness;
    267.         r.y += padding / 2;
    268.         r.x -= 2;
    269.         r.width += 6;
    270.         EditorGUI.DrawRect(r, linecolor);
    271.     }
    272. }
     
    Last edited: May 19, 2020
  6. Jaydeesale

    Jaydeesale

    Joined:
    Dec 31, 2017
    Posts:
    1
    1. var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    this line is always null for me ?

    anybody have any ideas, using windows if it helps at all, also has anyone tried this on 2019.4, it seems as tho the assetImporter doesn't work with 2019.4, no matter the path i throw at it comes back null, i even used a absolute path
     
  7. ooviixoo

    ooviixoo

    Joined:
    Dec 12, 2017
    Posts:
    11
    Amazing what you find when you need something! Thank you kindly for this.
     
  8. Enno

    Enno

    Joined:
    May 26, 2013
    Posts:
    4
    In case someone stumbles across this thread ... I have developed the above script even further. Added loads of options so that you can completely adjust the import process to your needs. Also fixed/improved the UI. Hope someone gets some use out of it. You'll find the tool under "Window-> Animation -> Animation Batch Import"

    Tested with Unity 2020.3.25f1 LTS

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.IO;
    3. using System.Linq;
    4. using UnityEditor;
    5. using UnityEngine;
    6. public class AnimationBatchImport : EditorWindow {
    7.   private static AnimationBatchImport editor;
    8.   private static int width = 300;
    9.   private static int height = 500;
    10.   private static int x = 0;
    11.   private static int y = 0;
    12.   private static List<string> allFiles = new List<string>();
    13.   private Vector2 scrollPos;
    14.  
    15.   private static Settings settings = new Settings();
    16.   private const string settings_prefs_path = nameof(AnimationBatchImport) + "_lastsettings";
    17.   private static Color linecolor = new Color32(128, 128, 128, 64);
    18.   [System.Serializable]
    19.   private class Settings {
    20.     public string path = string.Empty;
    21.     public bool rename_anim_clips = true;
    22.     public bool rename_anim_clips_underscores = true;
    23.     public bool rename_anim_clips_tolower = true;
    24.     public bool change_loop_anim_clips = true;
    25.     public bool loop_anim_clips_time = true;
    26.     public bool loop_anim_clips_pose = false;
    27.     public float loop_anim_clips_cycleoffset = 0f;
    28.     public bool root_transform_rotation = false;
    29.     public bool root_transform_rotation_bakeintopose = false;
    30.     public int root_transform_rotation_popupindex = 0;
    31.     public float root_transform_rotation_offset = 0f;
    32.     public bool root_transform_positiony = false;
    33.     public bool root_transform_positiony_bakeintopose = false;
    34.     public int root_transform_positiony_popupindex = 0;
    35.     public float root_transform_positiony_offset = 0f;
    36.     public bool root_transform_positionxz = false;
    37.     public bool root_transform_positionxz_bakeintopose = false;
    38.     public int root_transform_positionxz_popupindex = 0;
    39.  
    40.     public bool disable_material_import = true;
    41.     public bool mirror = false;
    42.     public bool set_rig_to_humanoid = true;
    43.     public Avatar rig_custom_avatar;
    44.   }
    45.  
    46.   [MenuItem("Window/Animation/Animation Batch Import")]
    47.   static void ShowEditor() {
    48.     editor = EditorWindow.GetWindow<AnimationBatchImport>();
    49.     CenterWindow();
    50.     LoadSettings();
    51.   }
    52.  
    53.   private void OnGUI() {
    54.     scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
    55.  
    56.     EditorGUILayout.BeginHorizontal();
    57.     if (GUILayout.Button("Select directory")) {
    58.       settings.path = EditorUtility.OpenFolderPanel("Select directory with files", "", "");
    59.     }
    60.     if (GUILayout.Button("Reset settings")) {
    61.       settings = new Settings();
    62.       SaveSettings();
    63.     }
    64.     EditorGUILayout.EndHorizontal();
    65.  
    66.     GUILayout.Label($"Path: {settings.path} ", EditorStyles.boldLabel);
    67.     GUILayout.Label($"Selected: {Selection.gameObjects.Length} assets", EditorStyles.boldLabel);
    68.  
    69.     bool pathvalid = !string.IsNullOrEmpty(settings.path) && Directory.Exists(settings.path);
    70.     if (!pathvalid) {
    71.       GUI.color = Color.red;
    72.       GUILayout.Label("Path invalid", EditorStyles.boldLabel);
    73.       GUI.color = Color.white;
    74.     }
    75.  
    76.     DrawUILine();
    77.     settings.rename_anim_clips = EditorGUILayout.BeginToggleGroup("Rename animation clips to filename", settings.rename_anim_clips);
    78.     {
    79.       settings.rename_anim_clips_underscores = EditorGUILayout.Toggle("Spaces to underscores", settings.rename_anim_clips_underscores);
    80.       settings.rename_anim_clips_tolower = EditorGUILayout.Toggle("To lowercase", settings.rename_anim_clips_tolower);
    81.     }
    82.     EditorGUILayout.EndToggleGroup();
    83.     GUILayout.Space(5);
    84.  
    85.     DrawUILine();
    86.     settings.change_loop_anim_clips = EditorGUILayout.BeginToggleGroup("Loop Time", settings.change_loop_anim_clips);
    87.     {
    88.       settings.loop_anim_clips_time = EditorGUILayout.Toggle("Loop Time", settings.loop_anim_clips_time);
    89.       settings.loop_anim_clips_pose = EditorGUILayout.Toggle("Loop Pose", settings.loop_anim_clips_pose);
    90.       settings.loop_anim_clips_cycleoffset = EditorGUILayout.FloatField("Cycle Offset", settings.loop_anim_clips_cycleoffset);
    91.     }
    92.     EditorGUILayout.EndToggleGroup();
    93.     GUILayout.Space(5);
    94.  
    95.     DrawUILine();
    96.     settings.root_transform_rotation = EditorGUILayout.BeginToggleGroup("Root Transform Rotation", settings.root_transform_rotation);
    97.     {
    98.       settings.root_transform_rotation_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_rotation_bakeintopose);
    99.       settings.root_transform_rotation_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_rotation_popupindex, new string[]{
    100.         "Original", "Body Orientation"
    101.       });
    102.       settings.root_transform_rotation_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_rotation_offset);
    103.     }
    104.     EditorGUILayout.EndToggleGroup();
    105.     GUILayout.Space(5);
    106.  
    107.     DrawUILine();
    108.     settings.root_transform_positiony = EditorGUILayout.BeginToggleGroup("Root Transform Position (Y)", settings.root_transform_positiony);
    109.     {
    110.       settings.root_transform_positiony_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_positiony_bakeintopose);
    111.       settings.root_transform_positiony_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_positiony_popupindex, new string[]{
    112.         "Original", "Center of Mass", "Feet"
    113.       });
    114.       settings.root_transform_positiony_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_positiony_offset);
    115.     }
    116.     EditorGUILayout.EndToggleGroup();
    117.     GUILayout.Space(5);
    118.  
    119.     DrawUILine();
    120.     settings.root_transform_positionxz = EditorGUILayout.BeginToggleGroup("Root Transform Position (XZ)", settings.root_transform_positionxz);
    121.     {
    122.       settings.root_transform_positionxz_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_positionxz_bakeintopose);
    123.       settings.root_transform_positionxz_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_positionxz_popupindex, new string[]{
    124.         "Original", "Center of Mass"
    125.       });
    126.     }
    127.     EditorGUILayout.EndToggleGroup();
    128.     GUILayout.Space(5);
    129.  
    130.     DrawUILine();
    131.     settings.set_rig_to_humanoid = EditorGUILayout.Toggle("Set Rig to Humanoid", settings.set_rig_to_humanoid);
    132.     settings.disable_material_import = EditorGUILayout.Toggle("Disable Material Import", settings.disable_material_import);
    133.     settings.mirror = EditorGUILayout.Toggle("Mirror", settings.mirror);
    134.     settings.rig_custom_avatar = EditorGUILayout.ObjectField("Custom Avatar", settings.rig_custom_avatar, typeof(Avatar), false) as Avatar;
    135.  
    136.     GUILayout.Space(30);
    137.     DrawUILine();
    138.     GUILayout.BeginHorizontal();
    139.  
    140.     GUI.enabled = pathvalid;
    141.     if (GUILayout.Button("Process directory")) {
    142.       process_dir();
    143.       SaveSettings();
    144.     }
    145.     GUI.enabled = Selection.gameObjects.Length > 0;
    146.     if (GUILayout.Button("Process selected assets")) {
    147.       processSelectedAssets();
    148.       SaveSettings();
    149.     }
    150.     GUI.enabled = true;
    151.     GUILayout.EndHorizontal();
    152.  
    153.     EditorGUILayout.EndScrollView();
    154.   }
    155.  
    156.   private static void SaveSettings() {
    157.     string json = EditorJsonUtility.ToJson(settings);
    158.     EditorPrefs.SetString(settings_prefs_path, json);
    159.   }
    160.  
    161.   private static void LoadSettings() {
    162.     settings = JsonUtility.FromJson<Settings>(EditorPrefs.GetString(settings_prefs_path));
    163.     if (settings == null)
    164.       settings = new Settings();
    165.   }
    166.  
    167.   public void process_dir() {
    168.     DirSearch(settings.path);
    169.  
    170.     if (allFiles.Count > 0) {
    171.       for (int i = 0; i < allFiles.Count; i++) {
    172.         int idx = allFiles[i].IndexOf("Assets");
    173.         string filename = Path.GetFileName(allFiles[i]);
    174.         string asset = allFiles[i].Substring(idx);
    175.         AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    176.             asset, typeof(AnimationClip));
    177.  
    178.         var fileName = Path.GetFileNameWithoutExtension(allFiles[i]);
    179.         var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    180.  
    181.         EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", filename, (1f / allFiles.Count) * i);
    182.  
    183.         RenameAndImport(importer, fileName);
    184.       }
    185.     }
    186.  
    187.     EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", "Saving assets", 1f);
    188.     AssetDatabase.SaveAssets();
    189.     EditorUtility.ClearProgressBar();
    190.  
    191.   }
    192.  
    193.   public void processSelectedAssets() {
    194.     int count = Selection.gameObjects.Length;
    195.     if (count > 0) {
    196.       for (int i = 0; i < count; i++) {
    197.         UnityEngine.Object asset = Selection.gameObjects[i];
    198.         string assetpath = AssetDatabase.GetAssetPath(asset);
    199.         AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    200.             assetpath, typeof(AnimationClip));
    201.  
    202.         var fileName = asset.name;
    203.         var importer = (ModelImporter)AssetImporter.GetAtPath(assetpath);
    204.  
    205.         EditorUtility.DisplayProgressBar($"Processing {count} files", fileName, (1f / count) * i);
    206.  
    207.         RenameAndImport(importer, fileName);
    208.       }
    209.     }
    210.  
    211.     EditorUtility.ClearProgressBar();
    212.  
    213.   }
    214.  
    215.   private void RenameAndImport(ModelImporter asset, string name) {
    216.     ModelImporter modelImporter = asset as ModelImporter;
    217.     ModelImporterClipAnimation[] clipAnimations = modelImporter.defaultClipAnimations;
    218.  
    219.     if (settings.disable_material_import)
    220.       modelImporter.materialImportMode = ModelImporterMaterialImportMode.None;
    221.  
    222.     if (settings.set_rig_to_humanoid)
    223.       modelImporter.animationType = ModelImporterAnimationType.Human;
    224.  
    225.     if (settings.rig_custom_avatar != null)
    226.       modelImporter.sourceAvatar = settings.rig_custom_avatar;
    227.  
    228.     if (settings.rename_anim_clips_underscores)
    229.       name = name.Replace(' ', '_');
    230.  
    231.     if (settings.rename_anim_clips_tolower)
    232.       name = name.ToLower();
    233.  
    234.     for (int i = 0; i < clipAnimations.Length; i++) {
    235.       var clip = clipAnimations[i];
    236.  
    237.       if (settings.rename_anim_clips)
    238.         clip.name = name;
    239.       if (settings.change_loop_anim_clips) {
    240.         clip.loopTime = settings.loop_anim_clips_time;
    241.         clip.loopPose = settings.loop_anim_clips_pose;
    242.         clip.cycleOffset = settings.loop_anim_clips_cycleoffset;
    243.         if (settings.root_transform_rotation) {
    244.           clip.lockRootRotation = settings.root_transform_rotation_bakeintopose;
    245.           clip.keepOriginalOrientation = settings.root_transform_rotation_popupindex == 0;
    246.           clip.rotationOffset = settings.root_transform_rotation_offset;
    247.         }
    248.         if (settings.root_transform_positiony) {
    249.           clip.lockRootHeightY = settings.root_transform_positiony_bakeintopose;
    250.           clip.keepOriginalPositionY = settings.root_transform_positiony_popupindex == 0;
    251.           clip.heightFromFeet = settings.root_transform_positiony_popupindex == 2;
    252.           clip.heightOffset = settings.root_transform_positiony_offset;
    253.         }
    254.         if (settings.root_transform_positionxz) {
    255.           clip.lockRootPositionXZ = settings.root_transform_positionxz_bakeintopose;
    256.           clip.keepOriginalPositionXZ = settings.root_transform_positionxz_popupindex == 0;
    257.         }
    258.       }
    259.     }
    260.  
    261.     modelImporter.clipAnimations = clipAnimations;
    262.     modelImporter.SaveAndReimport();
    263.   }
    264.  
    265.   private static void CenterWindow() {
    266.     editor = EditorWindow.GetWindow<AnimationBatchImport>();
    267.     x = (Screen.currentResolution.width - width) / 2;
    268.     y = (Screen.currentResolution.height - height) / 2;
    269.     editor.position = new Rect(x, y, width, height);
    270.   }
    271.  
    272.   static void DirSearch(string path) {
    273.     string[] fileInfo = Directory.GetFiles(path, "*.fbx", SearchOption.AllDirectories);
    274.     foreach (string file in fileInfo) {
    275.       if (file.EndsWith(".fbx"))
    276.         allFiles.Add(file);
    277.     }
    278.   }
    279.  
    280.   private static void DrawUILine(int thickness = 1, int padding = 5) {
    281.     Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
    282.     r.height = thickness;
    283.     r.y += padding / 2;
    284.     r.x -= 2;
    285.     r.width += 6;
    286.     EditorGUI.DrawRect(r, linecolor);
    287.   }
    288. }
     
  9. starfoxy

    starfoxy

    Joined:
    Apr 24, 2016
    Posts:
    184
    This is great! I randomly stumbled across this so thank you @Chocolade and thank you for the new version @Enno !
     
  10. MobiSlick

    MobiSlick

    Joined:
    Mar 30, 2017
    Posts:
    5
    100% you should toss this in the asset store or up on git
     
  11. MobiSlick

    MobiSlick

    Joined:
    Mar 30, 2017
    Posts:
    5
    Just had to keep it going. Here's my edit

    (adds a right-click option "RenameMixamoAnim" to the asset context menu in the project explorer)

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.IO;
    3. using System.Linq;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7.     public class AnimationBatchImport : EditorWindow
    8.     {
    9.         private static AnimationBatchImport editor;
    10.         private static int width = 300;
    11.         private static int height = 500;
    12.         private static int x = 0;
    13.         private static int y = 0;
    14.         private static List<string> allFiles = new List<string>();
    15.         private Vector2 scrollPos;
    16.  
    17.         private static Settings settings = new Settings();
    18.         private const string settings_prefs_path = nameof(AnimationBatchImport) + "_lastsettings";
    19.         private static Color linecolor = new Color32(128, 128, 128, 64);
    20.         [System.Serializable]
    21.         private class Settings
    22.         {
    23.             public string path = string.Empty;
    24.             public bool rename_anim_clips = true;
    25.             public bool rename_anim_clips_underscores = true;
    26.             public bool rename_anim_clips_tolower = true;
    27.             public bool change_loop_anim_clips = true;
    28.             public bool loop_anim_clips_time = true;
    29.             public bool loop_anim_clips_pose = false;
    30.             public float loop_anim_clips_cycleoffset = 0f;
    31.             public bool root_transform_rotation = false;
    32.             public bool root_transform_rotation_bakeintopose = false;
    33.             public int root_transform_rotation_popupindex = 0;
    34.             public float root_transform_rotation_offset = 0f;
    35.             public bool root_transform_positiony = false;
    36.             public bool root_transform_positiony_bakeintopose = false;
    37.             public int root_transform_positiony_popupindex = 0;
    38.             public float root_transform_positiony_offset = 0f;
    39.             public bool root_transform_positionxz = false;
    40.             public bool root_transform_positionxz_bakeintopose = false;
    41.             public int root_transform_positionxz_popupindex = 0;
    42.  
    43.             public bool disable_material_import = true;
    44.             public bool mirror = false;
    45.             public bool set_rig_to_humanoid = true;
    46.             public Avatar rig_custom_avatar;
    47.         }
    48.  
    49.         [MenuItem("Window/Animation/Animation Batch Import")]
    50.         static void ShowEditor()
    51.         {
    52.             editor = EditorWindow.GetWindow<AnimationBatchImport>();
    53.             CenterWindow();
    54.             LoadSettings();
    55.         }
    56.  
    57.         private void OnGUI()
    58.         {
    59.             scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
    60.  
    61.             EditorGUILayout.BeginHorizontal();
    62.             if (GUILayout.Button("Select directory"))
    63.             {
    64.                 settings.path = EditorUtility.OpenFolderPanel("Select directory with files", "", "");
    65.             }
    66.             if (GUILayout.Button("Reset settings"))
    67.             {
    68.                 settings = new Settings();
    69.                 SaveSettings();
    70.             }
    71.             EditorGUILayout.EndHorizontal();
    72.  
    73.             GUILayout.Label($"Path: {settings.path} ", EditorStyles.boldLabel);
    74.             GUILayout.Label($"Selected: {Selection.gameObjects.Length} assets", EditorStyles.boldLabel);
    75.  
    76.             bool pathvalid = !string.IsNullOrEmpty(settings.path) && Directory.Exists(settings.path);
    77.             if (!pathvalid)
    78.             {
    79.                 GUI.color = Color.red;
    80.                 GUILayout.Label("Path invalid", EditorStyles.boldLabel);
    81.                 GUI.color = Color.white;
    82.             }
    83.  
    84.             DrawUILine();
    85.             settings.rename_anim_clips = EditorGUILayout.BeginToggleGroup("Rename animation clips to filename", settings.rename_anim_clips);
    86.             {
    87.                 settings.rename_anim_clips_underscores = EditorGUILayout.Toggle("Spaces to underscores", settings.rename_anim_clips_underscores);
    88.                 settings.rename_anim_clips_tolower = EditorGUILayout.Toggle("To lowercase", settings.rename_anim_clips_tolower);
    89.             }
    90.             EditorGUILayout.EndToggleGroup();
    91.             GUILayout.Space(5);
    92.  
    93.             DrawUILine();
    94.             settings.change_loop_anim_clips = EditorGUILayout.BeginToggleGroup("Loop Time", settings.change_loop_anim_clips);
    95.             {
    96.                 settings.loop_anim_clips_time = EditorGUILayout.Toggle("Loop Time", settings.loop_anim_clips_time);
    97.                 settings.loop_anim_clips_pose = EditorGUILayout.Toggle("Loop Pose", settings.loop_anim_clips_pose);
    98.                 settings.loop_anim_clips_cycleoffset = EditorGUILayout.FloatField("Cycle Offset", settings.loop_anim_clips_cycleoffset);
    99.             }
    100.             EditorGUILayout.EndToggleGroup();
    101.             GUILayout.Space(5);
    102.  
    103.             DrawUILine();
    104.             settings.root_transform_rotation = EditorGUILayout.BeginToggleGroup("Root Transform Rotation", settings.root_transform_rotation);
    105.             {
    106.                 settings.root_transform_rotation_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_rotation_bakeintopose);
    107.                 settings.root_transform_rotation_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_rotation_popupindex, new string[]{
    108.         "Original", "Body Orientation"
    109.       });
    110.                 settings.root_transform_rotation_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_rotation_offset);
    111.             }
    112.             EditorGUILayout.EndToggleGroup();
    113.             GUILayout.Space(5);
    114.  
    115.             DrawUILine();
    116.             settings.root_transform_positiony = EditorGUILayout.BeginToggleGroup("Root Transform Position (Y)", settings.root_transform_positiony);
    117.             {
    118.                 settings.root_transform_positiony_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_positiony_bakeintopose);
    119.                 settings.root_transform_positiony_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_positiony_popupindex, new string[]{
    120.         "Original", "Center of Mass", "Feet"
    121.       });
    122.                 settings.root_transform_positiony_offset = EditorGUILayout.FloatField("Offset", settings.root_transform_positiony_offset);
    123.             }
    124.             EditorGUILayout.EndToggleGroup();
    125.             GUILayout.Space(5);
    126.  
    127.             DrawUILine();
    128.             settings.root_transform_positionxz = EditorGUILayout.BeginToggleGroup("Root Transform Position (XZ)", settings.root_transform_positionxz);
    129.             {
    130.                 settings.root_transform_positionxz_bakeintopose = EditorGUILayout.Toggle("Bake into pose", settings.root_transform_positionxz_bakeintopose);
    131.                 settings.root_transform_positionxz_popupindex = EditorGUILayout.Popup("Based Upon", settings.root_transform_positionxz_popupindex, new string[]{
    132.         "Original", "Center of Mass"
    133.       });
    134.             }
    135.             EditorGUILayout.EndToggleGroup();
    136.             GUILayout.Space(5);
    137.  
    138.             DrawUILine();
    139.             settings.set_rig_to_humanoid = EditorGUILayout.Toggle("Set Rig to Humanoid", settings.set_rig_to_humanoid);
    140.             settings.disable_material_import = EditorGUILayout.Toggle("Disable Material Import", settings.disable_material_import);
    141.             settings.mirror = EditorGUILayout.Toggle("Mirror", settings.mirror);
    142.             settings.rig_custom_avatar = EditorGUILayout.ObjectField("Custom Avatar", settings.rig_custom_avatar, typeof(Avatar), false) as Avatar;
    143.  
    144.             GUILayout.Space(30);
    145.             DrawUILine();
    146.             GUILayout.BeginHorizontal();
    147.  
    148.             GUI.enabled = pathvalid;
    149.             if (GUILayout.Button("Process directory"))
    150.             {
    151.                 process_dir();
    152.                 SaveSettings();
    153.             }
    154.             GUI.enabled = Selection.gameObjects.Length > 0;
    155.             if (GUILayout.Button("Process selected assets"))
    156.             {
    157.                 processSelectedAssets();
    158.                 SaveSettings();
    159.             }
    160.             GUI.enabled = true;
    161.             GUILayout.EndHorizontal();
    162.  
    163.             EditorGUILayout.EndScrollView();
    164.         }
    165.  
    166.         private static void SaveSettings()
    167.         {
    168.             string json = EditorJsonUtility.ToJson(settings);
    169.             EditorPrefs.SetString(settings_prefs_path, json);
    170.         }
    171.  
    172.         private static void LoadSettings()
    173.         {
    174.             settings = JsonUtility.FromJson<Settings>(EditorPrefs.GetString(settings_prefs_path));
    175.             if (settings == null)
    176.                 settings = new Settings();
    177.         }
    178.  
    179.         public void process_dir()
    180.         {
    181.             DirSearch(settings.path);
    182.  
    183.             if (allFiles.Count > 0)
    184.             {
    185.                 for (int i = 0; i < allFiles.Count; i++)
    186.                 {
    187.                     int idx = allFiles[i].IndexOf("Assets");
    188.                     string filename = Path.GetFileName(allFiles[i]);
    189.                     string asset = allFiles[i].Substring(idx);
    190.                     AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    191.                         asset, typeof(AnimationClip));
    192.  
    193.                     var fileName = Path.GetFileNameWithoutExtension(allFiles[i]);
    194.                     var importer = (ModelImporter)AssetImporter.GetAtPath(asset);
    195.  
    196.                     EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", filename, (1f / allFiles.Count) * i);
    197.  
    198.                     RenameAndImport(importer, fileName);
    199.                 }
    200.             }
    201.  
    202.             EditorUtility.DisplayProgressBar($"Processing {allFiles.Count} files", "Saving assets", 1f);
    203.             AssetDatabase.SaveAssets();
    204.             EditorUtility.ClearProgressBar();
    205.  
    206.         }
    207.  
    208.         // Add a menu item called "rename animation" to a FBX's context menu.
    209.         [MenuItem ("Assets/RenameMixamoAnim")]
    210.         static void RenameMixamoAnim () {
    211.             //Rigidbody body = (Rigidbody)command.context;
    212.             //body.mass = body.mass * 2;
    213.             Debug.Log ("Context: " + Selection.activeObject.ToString());
    214.             UnityEngine.Object asset = Selection.activeGameObject;
    215.             string assetpath = AssetDatabase.GetAssetPath(asset);
    216.             AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(assetpath, typeof(AnimationClip));
    217.             var fileName = asset.name;
    218.             var importer = (ModelImporter)AssetImporter.GetAtPath(assetpath);
    219.             RenameAndImport(importer, fileName);
    220.         }
    221.  
    222.         public void processSelectedAssets()
    223.         {
    224.             int count = Selection.gameObjects.Length;
    225.             if (count > 0)
    226.             {
    227.                 for (int i = 0; i < count; i++)
    228.                 {
    229.                     UnityEngine.Object asset = Selection.gameObjects[i];
    230.                     string assetpath = AssetDatabase.GetAssetPath(asset);
    231.                     AnimationClip orgClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(
    232.                         assetpath, typeof(AnimationClip));
    233.  
    234.                     var fileName = asset.name;
    235.                     var importer = (ModelImporter)AssetImporter.GetAtPath(assetpath);
    236.  
    237.                     EditorUtility.DisplayProgressBar($"Processing {count} files", fileName, (1f / count) * i);
    238.  
    239.                     RenameAndImport(importer, fileName);
    240.                 }
    241.             }
    242.  
    243.             EditorUtility.ClearProgressBar();
    244.  
    245.         }
    246.  
    247.  
    248.  
    249.         static void RenameAndImport(ModelImporter asset, string name)
    250.         {
    251.             ModelImporter modelImporter = asset as ModelImporter;
    252.             ModelImporterClipAnimation[] clipAnimations = modelImporter.defaultClipAnimations;
    253.  
    254.             if (settings.disable_material_import)
    255.                 modelImporter.materialImportMode = ModelImporterMaterialImportMode.None;
    256.  
    257.             if (settings.set_rig_to_humanoid)
    258.                 modelImporter.animationType = ModelImporterAnimationType.Human;
    259.  
    260.             if (settings.rig_custom_avatar != null)
    261.                 modelImporter.sourceAvatar = settings.rig_custom_avatar;
    262.  
    263.             if (settings.rename_anim_clips_underscores)
    264.                 name = name.Replace(' ', '_');
    265.  
    266.             if (settings.rename_anim_clips_tolower)
    267.                 name = name.ToLower();
    268.  
    269.             for (int i = 0; i < clipAnimations.Length; i++)
    270.             {
    271.                 var clip = clipAnimations[i];
    272.  
    273.                 if (settings.rename_anim_clips)
    274.                     clip.name = name;
    275.                 if (settings.change_loop_anim_clips)
    276.                 {
    277.                     clip.loopTime = settings.loop_anim_clips_time;
    278.                     clip.loopPose = settings.loop_anim_clips_pose;
    279.                     clip.cycleOffset = settings.loop_anim_clips_cycleoffset;
    280.                     if (settings.root_transform_rotation)
    281.                     {
    282.                         clip.lockRootRotation = settings.root_transform_rotation_bakeintopose;
    283.                         clip.keepOriginalOrientation = settings.root_transform_rotation_popupindex == 0;
    284.                         clip.rotationOffset = settings.root_transform_rotation_offset;
    285.                     }
    286.                     if (settings.root_transform_positiony)
    287.                     {
    288.                         clip.lockRootHeightY = settings.root_transform_positiony_bakeintopose;
    289.                         clip.keepOriginalPositionY = settings.root_transform_positiony_popupindex == 0;
    290.                         clip.heightFromFeet = settings.root_transform_positiony_popupindex == 2;
    291.                         clip.heightOffset = settings.root_transform_positiony_offset;
    292.                     }
    293.                     if (settings.root_transform_positionxz)
    294.                     {
    295.                         clip.lockRootPositionXZ = settings.root_transform_positionxz_bakeintopose;
    296.                         clip.keepOriginalPositionXZ = settings.root_transform_positionxz_popupindex == 0;
    297.                     }
    298.                 }
    299.             }
    300.  
    301.             modelImporter.clipAnimations = clipAnimations;
    302.             modelImporter.SaveAndReimport();
    303.         }
    304.  
    305.         private static void CenterWindow()
    306.         {
    307.             editor = EditorWindow.GetWindow<AnimationBatchImport>();
    308.             x = (Screen.currentResolution.width - width) / 2;
    309.             y = (Screen.currentResolution.height - height) / 2;
    310.             editor.position = new Rect(x, y, width, height);
    311.         }
    312.  
    313.         static void DirSearch(string path)
    314.         {
    315.             string[] fileInfo = Directory.GetFiles(path, "*.fbx", SearchOption.AllDirectories);
    316.             foreach (string file in fileInfo)
    317.             {
    318.                 if (file.EndsWith(".fbx"))
    319.                     allFiles.Add(file);
    320.             }
    321.         }
    322.  
    323.         private static void DrawUILine(int thickness = 1, int padding = 5)
    324.         {
    325.             Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
    326.             r.height = thickness;
    327.             r.y += padding / 2;
    328.             r.x -= 2;
    329.             r.width += 6;
    330.             EditorGUI.DrawRect(r, linecolor);
    331.         }
    332.     }
     
  12. fnnbrr

    fnnbrr

    Joined:
    Jan 26, 2021
    Posts:
    11
    Here's similar functionality for renaming Mixamo animations implemented as an AssetPostprocessor. This will just run in the background and automatically rename any "mixamo.com" animation it finds, both on assets already in the project and new ones that are imported for the first time. Tested on 2021.3.24f1.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.IO;
    3. using UnityEditor;
    4. using UnityEngine;
    5.  
    6. public class AnimationRenamingProcessor : AssetPostprocessor
    7. {
    8.     // Include any AnimationClip names here that should be automatically replaced
    9.     private static readonly HashSet<string> NamesToReplace = new()
    10.     {
    11.         "mixamo.com"
    12.     };
    13.  
    14.     private string NewName => Path.GetFileNameWithoutExtension(context.assetPath);
    15.  
    16.     private void OnPostprocessModel(GameObject gameObject)
    17.     {
    18.         if (assetImporter is not ModelImporter modelImporter) return;
    19.      
    20.         ModelImporterClipAnimation[] clipAnimations = modelImporter.clipAnimations;
    21.  
    22.         if (clipAnimations.Length < 1)
    23.         {
    24.             // Try to use the existing clipAnimations if they exist to preserve other settings (e.g. AnimationEvents),
    25.             // but fallback to creating new clipAnimations from the defaultClipAnimations
    26.             clipAnimations = modelImporter.defaultClipAnimations;
    27.         }
    28.  
    29.         bool isDirty = false;
    30.  
    31.         foreach (ModelImporterClipAnimation clipAnimation in clipAnimations)
    32.         {
    33.             if (NamesToReplace.Contains(clipAnimation.name))
    34.             {
    35.                 clipAnimation.name = NewName;
    36.                 isDirty = true;
    37.             }
    38.         }
    39.  
    40.         if (isDirty)  // To prevent needlessly setting new clipAnimations in case of any side effects
    41.         {
    42.             modelImporter.clipAnimations = clipAnimations;
    43.         }
    44.     }
    45.  
    46.     private void OnPostprocessAnimation(GameObject root, AnimationClip clip)
    47.     {
    48.         if (NamesToReplace.Contains(clip.name))
    49.         {
    50.             clip.name = NewName;
    51.         }
    52.     }
    53. }
     
    H4CK3RD4WG and xjjon like this.
  13. willardj

    willardj

    Joined:
    Feb 23, 2019
    Posts:
    2
    Excellent work guys!