700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > unity导出fbx模型_Unity批量合并Animation工具/根据已有的Animation文件批量生成带FBX动画工具...

unity导出fbx模型_Unity批量合并Animation工具/根据已有的Animation文件批量生成带FBX动画工具...

时间:2021-09-24 00:37:09

相关推荐

unity导出fbx模型_Unity批量合并Animation工具/根据已有的Animation文件批量生成带FBX动画工具...

由于本人现有项目的项目素材大部分都需要继续沿用旧项目的模型与动画,但在接受旧模型动画的时候发现,模型动画由于外包已经丢失了3dmax的源文件,只剩下了一堆AnimationCilp(.anim)文件与一个带骨架的动画模型。

如果美术提出一个需求,需要在原有的动作上做出一些修改,那我们就必须要把已有的.anim文件反导出成.fbx文件,供美术修改。

这时我们就要用到Unity一款非常便捷的插件:FBX Exporter

FBX Exporter可以在Packages Manager中直接下载

我们只需要在场景中拖入我们的动画模型,并加上Animator组件,然后把AnimationCilp(.anim)文件拉入Animator中,然后在右键菜单中选择Export to FBX..就可以导出一个带动画的.fbx文件。

生成出来的.Fbx文件会遍历Animator组件中的所有的AnimationCilp然后生成到对应的Fbx文件中。

但是这个如果我们将这个.fbx发给美术,美术如果使用3dmax打开,会发现3dmax只会默认打开第一个动作,而无法打开其余的其他动作...(但是亲测C4D在导入时,是可以给玩家选择导入不同的动画片段的)

这时我们只有两种选择:

提取所有的.anim文件里的帧信息都合并成一个大的.anim文件自动为不同的.anim文件生成一个对用的.fbx文件

基于以上两个需求,我的工具就应运而生了~

将AnimationDefineEditor.cs与AnimationExport.cs放入Editor中

使用批量合批动画工具可以提取目标动画机Animator中所有的AnimationCilp的帧信息然后合并成一个大的.anim文件,保存在对应的输出路径下。

动作间隔是指两个AnimationCilp之间的间隔。

Warning:但是该工具只适用于未经过优化的动画,如果动画是经过了优化的,上一个Cilp的尾帧会作用到下一个Cilp。

使用批量生成Fbx工具,在AnimationClips选项中拖入你需要导出的.anim文件,然后点击Cenerate按钮,则可以批量生成对应的.fbx文件,生成的fbx文件名字由.anim文件控制。

Warning:拖入工具的目标物体不能带有Animator组件!!!否则输出的.fbx则优先输出Animator中的动画信息。

using System.Collections.Generic;using UnityEngine;using UnityEditor;public class AnimationExport{private float index;/// <summary>/// name为动作名称/// space为每个动作之间的间隔,秒为单位/// </summary>/// <param name="animator"></param>/// <param name="name"></param>/// <param name="space"></param>public void Export(Animator animator,string name,float space,int frameRate,string path){var animationPath = "Assets/" + name + ".anim";if (AssetDatabase.IsValidFolder(path)){animationPath = path;}var output_clip = new AnimationClip(){name = name,legacy = false,wrapMode = WrapMode.Once,frameRate = frameRate};index = 0;RuntimeAnimatorController ac = animator.runtimeAnimatorController;AnimationClip[] ori_clips = ac.animationClips;if (null == ori_clips || ori_clips.Length <= 0) return;AnimationClip current_clip;for (int i = 0, length = ori_clips.Length; i < length; i++){current_clip = ac.animationClips[i];if (current_clip != null){float keys_lenght = AnimCopy(current_clip, ref output_clip, index);index += keys_lenght + space;}}AssetDatabase.CreateAsset(output_clip, animationPath); //AssetDatabase中的路径都是相对Asset的 如果指定路径已存在asset则会被删除,然后创建新的assetAssetDatabase.SaveAssets();//保存修改AssetDatabase.Refresh();}/// <summary>/// name为动作名称/// space为每个动作之间的间隔,秒为单位/// </summary>/// <param name="animator"></param>/// <param name="name"></param>/// <param name="space"></param>public void Export(GameObject obj, List<AnimationClip> clips, string name){ AnimationClip current_clip;for (int i = 0, length = clips.Count; i < length; i++){current_clip = clips[i];if (current_clip != null){current_clip.legacy = true;var _animation = obj.GetComponent<Animation>();if (_animation != null){GameObject.DestroyImmediate(_animation);}_animation = obj.AddComponent<Animation>();var _name = current_clip.name;var animationPath = "Assets/" + _name + ".fbx";_animation.AddClip(current_clip, _name);_animation.clip = current_clip;UnityEditor.Formats.Fbx.Exporter.ModelExporter.ExportObject(animationPath, _animation);}}}float AnimCopy(AnimationClip srcClip, ref AnimationClip outputClip, float start_index){//AnimationClipSettings setting = AnimationUtility.GetAnimationClipSettings(srcClip);//获取AnimationClipSettings//AnimationUtility.SetAnimationClipSettings(newClip, setting);//设置新clip的AnimationClipSettings//newClip.frameRate = srcClip.frameRate;//设置新clip的帧率float keys_count_max = 0;EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(srcClip);//获取clip的curveBindskeys_count_max = srcClip.length;for (int i = 0; i < curveBindings.Length; i++){AnimationCurve ori_curve = AnimationUtility.GetEditorCurve(srcClip, curveBindings[i]);AnimationCurve output_curve = AnimationUtility.GetEditorCurve(outputClip, curveBindings[i]);AnimationCurve new_curve = new AnimationCurve();if (output_curve != null && output_curve.length > 0){for (int j = 0; j < output_curve.keys.Length; j++){new_curve.AddKey(output_curve.keys[j].time, output_curve.keys[j].value);}}if (ori_curve != null && ori_curve.length > 0){for (int j = 0; j < ori_curve.keys.Length; j++){new_curve.AddKey(start_index + ori_curve.keys[j].time, ori_curve.keys[j].value);}}AnimationUtility.SetEditorCurve(outputClip, curveBindings[i], new_curve);}return keys_count_max;}}

using System.Collections.Generic;using UnityEditor;using UnityEngine;public class AnimationExportWindow: EditorWindow{public static GameObject targetGo;private static AnimationExport baker;private static string path = "Asset/";private static string animator_name = "Default";private static float space = 0f;private static int frameRate = 30;[SerializeField]//必须要加 protected List<UnityEngine.AnimationClip> _animationClips = new List<UnityEngine.AnimationClip>();//序列化对象 protected SerializedObject _serializedObject;//序列化属性 protected SerializedProperty _assetLstProperty;GUIStyle fontSytle1;private void OnEnable(){fontSytle1 = new GUIStyle();fontSytle1.fontSize = 15;fontSytle1.normal.textColor = Color.yellow;fontSytle1.fontStyle = FontStyle.Bold;fontSytle1.alignment = TextAnchor.MiddleCenter;fontSytle1.wordWrap = true;//使用当前类初始化 _serializedObject = new SerializedObject(this);//获取当前类中可序列话的属性 _assetLstProperty = _serializedObject.FindProperty("_animationClips");}[MenuItem("Art Tools/AnimationExport")]public static void ShowWindow(){var win = EditorWindow.GetWindow(typeof(AnimationExportWindow));baker = new AnimationExport();win.Show();}void OnGUI(){GUILayout.BeginVertical("box");GUILayout.Space(10f);GUILayout.Label("-批量合批动画工具-", fontSytle1);GUILayout.Space(10f);targetGo = (GameObject)EditorGUILayout.ObjectField("目标动画机(Animator):",targetGo, typeof(GameObject), true);animator_name = EditorGUILayout.TextField("输出动作名称(name):", animator_name);path = EditorGUILayout.TextField("输出路径(path):", path);space = EditorGUILayout.FloatField("动作间隔(space/s):", space);frameRate = EditorGUILayout.IntField("帧率(frameRate):", frameRate);var animationPath = "Assets/" + animator_name + ".anim";if (!string.IsNullOrEmpty(path) &&!string.IsNullOrEmpty(System.IO.Path.GetDirectoryName(path)) &&System.IO.Directory.Exists(path)){animationPath = path;}GUILayout.Label("输出路径(output_path):" + animationPath);if (GUILayout.Button("Generate")){if (targetGo == null){EditorUtility.DisplayDialog("err", "目标动画机 is null!", "OK");return;}if (baker == null){baker = new AnimationExport();}var animator = targetGo.GetComponent<Animator>();if (animator == null){EditorUtility.DisplayDialog("err", "Animator is null!", "OK");return;}baker.Export(animator, animator_name, space, frameRate, animationPath);}GUILayout.EndVertical();GUILayout.BeginVertical("box");GUILayout.Space(10f);GUILayout.Label("-批量生成Fbx工具-", fontSytle1);GUILayout.Space(10f);targetGo = (GameObject)EditorGUILayout.ObjectField("目标物体", targetGo, typeof(GameObject), true);if (GUILayout.Button("Generate")){if (targetGo == null){EditorUtility.DisplayDialog("err", "目标物体为空!", "OK");return;}if (baker == null){baker = new AnimationExport();}if (_animationClips.Count <= 0){EditorUtility.DisplayDialog("err", "AnimationClips is null!", "OK");return;}baker.Export(targetGo,_animationClips, animator_name);}//更新 _serializedObject.Update();//开始检查是否有修改 EditorGUI.BeginChangeCheck();//显示属性 //第二个参数必须为true,否则无法显示子节点即List内容 EditorGUILayout.PropertyField(_assetLstProperty, true);//结束检查是否有修改 if (EditorGUI.EndChangeCheck()){//提交修改 _serializedObject.ApplyModifiedProperties();}GUILayout.EndVertical();}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。