主要参考该文章:人无两度s 《unity自动切割动画》 感谢作者分享
执行代码需要将模型与配置文件(.txt)放到同一目录下,批量选中模型后右键,代码中读取了选中的第一个模型同目录下可能存在的“动画帧分段.txt”,按其中的配置对选中的模型进行动画片段切分。
配置文件每行的格式:【帧数】,空格,【动画名】,空格,【模型1、模型2】
示例:
代码:
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections.Generic;
using System.IO;
using System;
using System.Linq;
//txt文件,命名为"动画帧分段",与模型位于同一目录下,每行格式为[帧数(例如”100-200“),空格,动画名(xxxx),模型名(xx、xx)]
public class AniAutoCut : Editor
{
public static Dictionary<string, List<AniCutConfig>> configs;
public static string filePath;
[MenuItem("Assets/一键切割动画")]
public static void StartCutAni()
{
UnityEngine.Object[] objs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets);
configs = new();
foreach (var obj in objs)
{
Debug.Log(obj.name);
configs[obj.name] = new List<AniCutConfig>();
}
ReadConfig(AssetDatabase.GetAssetPath(objs[0]));
BatchCut();
}
private static void BatchCut()
{
foreach (KeyValuePair<string, List<AniCutConfig>> kvp in configs)
{
CutAni(filePath + kvp.Key + ".fbx", kvp.Value);
}
}
private static void ReadConfig(string path)
{
//获取配置路径
string[] tempPath = path.Split('/');
filePath = "";
foreach (string i in tempPath)
{
if (!i.Contains(".fbx"))
{
filePath += (i + "/");
}
}
//数据处理
if (File.Exists(filePath + "动画帧分段.txt"))
{
string file = File.ReadAllText(filePath + "动画帧分段.txt");
if (file.Contains("\n"))
{
//拆分成行
string[] arr = file.Split('\n');
for (int i = 0; i < arr.Length; i++)
{
if (!string.IsNullOrEmpty(arr[i]))
{
string[] item = arr[i].Split(" ", StringSplitOptions.RemoveEmptyEntries);
//标准格式行"XX XX XX"
if (item.Length == 3)
{
AniCutConfig acc = new();
acc.startFrame = int.Parse(item[0].Trim().Split("-")[0]);
acc.endFrame = int.Parse(item[0].Trim().Split("-")[1]);
acc.aniName = item[1].Trim();
string[] ModelNames = item[2].Split("、", StringSplitOptions.RemoveEmptyEntries);
foreach (string ModelName in ModelNames)
{
if (configs.Keys.Contains(ModelName.Trim()))
{
configs[ModelName.Trim()].Add(acc);
//Debug.Log(ModelName + " " + acc.startFrame + " " + acc.endFrame + " " + acc.aniName);
}
}
}
}
}
}
}
else
{
Debug.LogError("在动画路径下未找到\"动画帧分段.txt\"文件!");
}
}
//传入模型路径与帧数列表
private static void CutAni(string path, List<AniCutConfig> list)
{
ModelImporter model = AssetImporter.GetAtPath(path) as ModelImporter;
List<ModelImporterClipAnimation> clipAnimations = new List<ModelImporterClipAnimation>();
for (int i = 0; i < list.Count; i++)
{
ModelImporterClipAnimation clip = new ModelImporterClipAnimation();
clip.name = list[i].aniName;
clip.firstFrame = list[i].startFrame;
clip.lastFrame = list[i].endFrame;
//clip.loopPose = false;
clipAnimations.Add(clip);
}
model.clipAnimations = clipAnimations.ToArray();
model.SaveAndReimport();
AssetDatabase.ImportAsset(path);
AssetDatabase.Refresh();
}
}
public class AniCutConfig
{
public int startFrame;
public int endFrame;
public string aniName;
}