Unity3D 导入脚本のAnimation动画切割

原创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 Unity3D引擎技术交流QQ群:【119706192本文链接地址: Unity3D 导入脚本のAnimation动画切割

近期项目中为了缩减资源包,想把一个角色的所有动作全部放在原始模型模型中(后期证实,并无优化效果,所以把动作文件和原始模型文件又拆分成了单独的文件)。

原始模型中有600多帧动作,需要手动设置AnimationClip的起始帧和结束帧还有是否循环,。每个模型30个动作,一共25个主角模型,想想都蛋疼。于是研究了下unity的资源处理器(AssetPostprocessor)。

在导入模型之前(OnPreprocessModel)对动画进行切割。

1.首先导入脚本不可能智能到知道我们的某个动作的动作名、开始帧、结束帧和是否循环,这个时候就需要一个配置表。
  • 为了让结构更加清晰,我把这几个需要导表的数据用类封装一下,这个类是一个AnimationClip需要的数据。
  • clipST这个类只记录一个AnimationClip的数据,一个模型会有N个AnimationClip组成,所以还要有一个类(modelst)来封装这一堆AnimationClip。并且还要记录这堆AnimationClip是给哪个模型用的。
  • 然后用一个List存储所有modelst。
  • 最后我们用init()方法,把美工提供的动作信息这些写入结构即可。

具体代码如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
//自定义的动作配置表(用来预先配置各动作的动作名、起始帧、结束帧和是否循环。)
public static class AnimationClipConfig
{
    //是否已经初始化
    public static bool isInit = false;
    //模型动作配置表(只记录需要配置模型动作的模型)
    public static List<modelST> modelList = new List<modelST>();
 
    public static void init()
    {
        if (isInit)
            return;
        isInit = true;
 
        modelST tempModel = new modelST();
        //需要配置动作的模型名字
        tempModel.ModelName = "id_3000";
        //给该模型配置的动作(动作名、起始帧、结束帧、是否循环)
        tempModel.clipSTs = new clipST[]{
            new clipST("stand01" , 0, 60, true),         
            new clipST("stand02" , 143, 193, true),       
            new clipST("stand01_to_02" , 61, 100, false),  
            new clipST("stand02_to_01" , 120, 142, false),
 
            new clipST("shouji01" , 101, 119, false), 
            new clipST("run01" , 253, 275, true),           
 
            new clipST("jump01" , 606, 626, false),       
            new clipST("jump01_01" , 627, 645, false),     
            new clipST("jump02" , 646, 663, false),       
            new clipST("jump02_01" , 664, 686, false),      
            new clipST("jump02_atk01" , 687, 714, false), 
            new clipST("jump02_atk02" , 442, 456, false),   
 
            new clipST("1atk01" , 275, 285, false),       
            new clipST("1atk02" , 297, 317, false),         
            new clipST("1atk03" , 329, 349, false),    
            new clipST("1atk04_end" , 361, 381, false),  
 
            new clipST("1atk01_01" , 286, 296, false),      
            new clipST("1atk02_01" , 318, 328, false),       
            new clipST("1atk03_01" , 350, 360, false), 
 
            new clipST("2atk01" , 382, 392, false),       
            new clipST("2atk02" , 404, 424, false),         
            new clipST("2atk03" , 436, 456, false),      
            new clipST("2atk04_end" , 468, 488, false), 
 
            new clipST("2atk01_01" , 393, 403, false),      
            new clipST("2atk02_01" , 425, 435, false),       
            new clipST("2atk03_01" , 457, 467, false),  
 
            new clipST("3atk01" , 489, 499, false),       
            new clipST("3atk02" , 521, 541, false),         
            new clipST("3atk03" , 553, 573, false),       
            new clipST("3atk04_end" , 585, 605, false), 
 
            new clipST("3atk01_01" , 500, 520, false),      
            new clipST("3atk02_01" , 542, 552, false),       
            new clipST("3atk03_01" , 574, 584, false),      
 
            new clipST("xl_atk01_01" , 194, 252 , false),      
            new clipST("xl_atk01_02" , 194, 252, true),
            new clipST("xl_atk01_03" , 194, 252, false),      
 
            new clipST("dead01" , 715, 745, false), 
        };
        modelList.Add(tempModel);
 
 
    }
 
    #region ST
    //动作配置格式
    public class clipST
    {
        public string name;
        public int firstFrame;
        public int lastFrame;
        public bool isloop;
 
        public clipST(string _n,int _f,int _l,bool _i) {
            name = _n;
            firstFrame = _f;
            lastFrame = _l;
            isloop = _i;
        }
    }
    //模型动作表配置搁置
    public class modelST{
        public string ModelName;
        public clipST[] clipSTs;
    }
    #endregion
}
2.知道了数据,然后就是高端洋气的自动切割AnimationClip了。直接上代码:

using UnityEditor;
using UnityEngine;
 
public class FBXAnimationsFix : AssetPostprocessor
{
    public void OnPreprocessModel()
    {
        //当前正在导入的模型
        ModelImporter modelImporter = (ModelImporter) assetImporter;
        //初始化配置表
        AnimationClipConfig.init();
 
        //遍历模型动作配置表,获取每个需要配置动作的模型
        foreach (AnimationClipConfig.modelST item in AnimationClipConfig.modelList)
        {
            //当前导入模型的路径 ↓
            //包含我们配置表中的模型名字(即AnimationClipConfig.modelList.ModelName),
            //那就要对这个模型的动画进行切割
            if (assetPath.Contains(item.ModelName))
            {
                //先将导入模型的动画类型(Rig)设置成成legacy动画
                modelImporter.animationType = ModelImporterAnimationType.Legacy;
                modelImporter.generateAnimations = ModelImporterGenerateAnimations.GenerateAnimations;
 
                //记录模型动作数组的修改
                ModelImporterClipAnimation[] animations = new ModelImporterClipAnimation[item.clipSTs.Length];
                for (int i = 0; i < item.clipSTs.Length; i++)
                {
                    //将配置表的动作clip的名字、起始帧、结束帧和是否循环属性保存到动作clip数组(animations[])。
                    animations = SetClipAnimation(item.clipSTs.name, item.clipSTs.firstFrame, item.clipSTs.lastFrame, item.clipSTs.isloop);
                }
 
                //将修改后的动作数组设置给导入模型的动作数组
                modelImporter.clipAnimations = animations;
            }
        }
    }
}
 
ModelImporterClipAnimation SetClipAnimation(string _name, int _first, int _last, bool _isLoop)
{
    ModelImporterClipAnimation tempClip = new ModelImporterClipAnimation();
    tempClip.name = _name;
    tempClip.firstFrame = _first;
    tempClip.lastFrame = _last;
    tempClip.loop = _isLoop;
    if (_isLoop)
        tempClip.wrapMode = WrapMode.Loop;
    else
        tempClip.wrapMode = WrapMode.Default;
 
    return tempClip;
}

后来逐渐发现,讲所有动作合并到原始模型中并没有起到多少优化的作用,反而对维护增添了很多不必要的麻烦,后来又把动作切割开了。
动作和原始模型分成单独文件后,每个动作文件导入unity时,还会“非常智能”的把关联的材质、贴图再创建一个.fbm的文件夹导入一遍,但是我们原始模型已经导入了一套材质和贴图,动作就没必要再带进来一堆。所以要对动作进行一个设置,让他们不关联材质。

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
 
public class FBXScaleFix : AssetPostprocessor
{
    public void OnPreprocessModel()
    {
        ModelImporter modelImporter = (ModelImporter) assetImporter;
 
        if (assetPath.Contains("@"))
        {
            modelImporter.importMaterials = false;
        }
    }
}



你可能感兴趣的:(Unity3D 导入脚本のAnimation动画切割)