zoukankan      html  css  js  c++  java
  • Unity3D读取模型文件自动生成AnimatorController简单实例

    前几天接到一个任务,做一个导入、控制模型动画的工具类,没有太具体的要求,于是就自行思考实际需求,最终根据宣雨松老师的一篇博客,自己规范了一下写了一个工具类。相关工具代码及测试用例已上传至Github。

    https://github.com/hcy12321/UnityAnimatorControllerMaker

    该demo需在导入Unity后执行菜单Tools/CreateAnimator项后再执行。

    1.需求及规范

    需求是指实际使用时需要实现的地方,规范是最终使用这套工具需要遵守的规则。

    1.1 实际需求

    1. 能自动遍历fbx文件,且生成对应的AnimatorController文件。

    2. 能获取fbx文件中所有的动画片段(AnimationClip),并存入第一步生成的AnimatorController的状态机中。

    3.(个人假设需求)状态机默认指向一个空的动画。 

    1.2 使用规范

    1. 所有fbx文件需放置在Assets/Resources/fbx目录(该目录可在代码中更改)中的子目录中,该子目录以fbx名称(不可包含中文)命名,将fbx文件和贴图放到该子目录中,然后将fbx文件重命名为原名_model。

    如:wukong.fbx。因和其贴图一起放置在 AssetsResourcesfbxwukong目录中,然后改名为wukong_model.fbx。

    2.功能实现

    该部分主要介绍逻辑功能代码

    2.1 生成菜单方法

    在Editor目录下添加类文件AnimatorTool.cs,该类共有三个方法:

    void CreateAnimationAssets(): 工具菜单方法,内有遍历目录生成动画控制器、生成预设的逻辑

    using System;
    using UnityEngine;
    using System.Collections;
    using System.IO;
    using System.Linq;
    using UnityEditor;
    using UnityEditor.Animations;
    
    public class AnimatorTool : MonoBehaviour
    {
    
        /// <summary>
        /// 菜单方法,遍历文件夹创建Animation Controller
        /// </summary>
        [MenuItem("Tools/CreateAnimator")]
        static void CreateAnimationAssets()
        {
            string rootFolder = "Assets/Resources/fbx/";
            if (!Directory.Exists(rootFolder))
            {
                Directory.CreateDirectory(rootFolder);
                return;
            }
            // 遍历目录,查找生成controller文件
            var folders = Directory.GetDirectories(rootFolder);
            foreach (var folder in folders)
            {
                DirectoryInfo info = new DirectoryInfo(folder);
                string folderName = info.Name;
                // 创建animationController文件
                AnimatorController aController =
                    AnimatorController.CreateAnimatorControllerAtPath(string.Format("{0}/animation.controller", folder));
                // 得到其layer
                var layer = aController.layers[0];
                // 绑定动画文件
                AddStateTranstion(string.Format("{0}/{1}_model.fbx", folder, folderName), layer);
                // 创建预设
                GameObject go = LoadFbx(folderName);
                PrefabUtility.CreatePrefab(string.Format("{0}/{1}.prefab", folder, folderName), go);
                DestroyImmediate(go);
            }
    
    
        }
    
        /// <summary>
        /// 添加动画状态机状态
        /// </summary>
        /// <param name="path"></param>
        /// <param name="layer"></param>
        private static void AddStateTranstion(string path, AnimatorControllerLayer layer)
        {
            AnimatorStateMachine sm = layer.stateMachine;
            // 根据动画文件读取它的AnimationClip对象
            var datas = AssetDatabase.LoadAllAssetsAtPath(path);
            if (datas.Length == 0)
            {
                Debug.Log(string.Format("Can't find clip in {0}", path));
                return;
            }
            // 先添加一个默认的空状态
            var emptyState = sm.AddState("empty");
            sm.AddAnyStateTransition(emptyState);
            // 遍历模型中包含的动画片段,将其加入状态机中
            foreach (var data in datas)
            {
                if (!(data is AnimationClip))
                    continue;
                var newClip = data as AnimationClip;
                if (newClip.name.StartsWith("__"))
                    continue;
                // 取出动画名字,添加到state里面
                var state = sm.AddState(newClip.name);
                state.motion = newClip;
                // 把State添加在Layer里面
                sm.AddAnyStateTransition(state);
            }
    
        }
    
        /// <summary>
        /// 生成带动画控制器的对象
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static GameObject LoadFbx(string name)
        {
            var obj = Instantiate(Resources.Load(string.Format("fbx/{0}/{0}_model", name))) as GameObject;
            obj.GetComponent<Animator>().runtimeAnimatorController =
                Resources.Load<RuntimeAnimatorController>(string.Format("fbx/{0}/animation", name));
            return obj;
        }
    }

    2.2 测试用例

    测试用例中主要包含如何调用播放动画、暂停动画、重播动画等功能。

    using UnityEngine;
    using System.Collections;
    
    public class AnimatorTest : MonoBehaviour
    {
        private Animator animator;
    
        public string animationName = "run";
    
        public float Speed = 1.0f;
        // Use this for initialization
        void Start()
        {
            animator = GetComponent<Animator>();
        }
    
        /// <summary>
        /// 添加一些测试功能按钮
        /// </summary>
        void OnGUI()
        {
    #if UNITY_EDITOR
            if (GUILayout.Button("Play"))
            {
                Play(animationName);
            }
            if (GUILayout.Button("Replay"))
            {
                RePlay(animationName);
            }
            if (GUILayout.Button("Pause"))
            {
                Pause();
            }
    #endif
        }
    
        /// <summary>
        /// 设置速度
        /// </summary>
        /// <param name="speed"></param>
        public void SetSpeed(float speed)
        {
            Speed = speed;
        }
    
        /// <summary>
        /// 重新播放指定名称动画
        /// </summary>
        /// <param name="name"></param>
        public void RePlay(string name)
        {
            animator.speed = Speed;
            animator.Play(name, 0, 0.0f);
        }
    
        /// <summary>
        /// 播放指定名称动画
        /// </summary>
        /// <param name="name"></param>
        public void Play(string name)
        {
            animator.speed = Speed;
            animator.Play(name);
        }
    
        /// <summary>
        /// 暂停动画
        /// </summary>
        public void Pause()
        {
            animator.speed = 0.0f;
        }
    }

    3.总结

    该工具在项目实际使用中还有许多待优化的地方,如只考虑了一个模型,如果是一个人物有多个模型那么还要根据需求再重新设计。还有状态机中还没有根据模型直接生成结构动画、序列动画的功能,需要在以后继续改进。

    本工具参考了宣雨松老师的一篇博客:http://www.xuanyusong.com/archives/2811

    如有问题请指正,谢谢!

  • 相关阅读:
    【POJ 3162】 Walking Race (树形DP-求树上最长路径问题,+单调队列)
    【POJ 2152】 Fire (树形DP)
    【POJ 1741】 Tree (树的点分治)
    【POJ 2486】 Apple Tree (树形DP)
    【HDU 3810】 Magina (01背包,优先队列优化,并查集)
    【SGU 390】Tickets (数位DP)
    【SPOJ 2319】 BIGSEQ
    【SPOJ 1182】 SORTBIT
    【HDU 5456】 Matches Puzzle Game (数位DP)
    【HDU 3652】 B-number (数位DP)
  • 原文地址:https://www.cnblogs.com/yaoh/p/5149568.html
Copyright © 2011-2022 走看看