美文网首页
Unity中动画文件压缩优化

Unity中动画文件压缩优化

作者: Francis_Rose | 来源:发表于2020-01-20 14:32 被阅读0次

    这两天简单看了一下Unity的动画文件的优化,主要参考下面两篇
    (https://blog.uwa4d.com/archives/Optimization_Animation.html) Unity动画文件优化探究
    (https://blog.csdn.net/u013917120/article/details/79824448) Unity实用案例之——动画压缩
    (https://www.cnblogs.com/wayland/p/7131055.html) unity的animation动画资源压缩

    其中压缩的主要思路有两点:

    1. 移除scale曲线

    foreach(AnimationClip animClip in tAnimationClipList)
    {
        foreach(EditorCurveBinding curveBinding in AnimationUtility.GetCurveBindings(animClip))
        {
            string tName = curveBinding.propertyName.ToLower();
            if(tName.Contains("scale"))
            {
                AnimationUtility.SetEditorCurve(animClip, curveBinding, null);
      }
     }
     CompressAnimationClip(animClip);
    }
    

    2. 压缩精度

    public  static  void CompressAnimationClip(AnimationClip _clip) 
    {
        AnimationClipCurveData[] tCurveArr = AnimationUtility.GetAllCurves(_clip); 
        Keyframe tKey; 
        Keyframe[] tKeyFrameArr; 
        for(int i = 0; i < tCurveArr.Length; ++i) 
        { 
            AnimationClipCurveData tCurveData = tCurveArr[i]; 
            if(tCurveData.curve == null || tCurveData.curve.keys == null)
            { 
                continue; 
            }
            tKeyFrameArr = tCurveData.curve.keys; 
            for(int j = 0; j < tKeyFrameArr.Length; j++) 
            { 
                tKey = tKeyFrameArr[j]; 
                tKey.value = float.Parse(tKey.value.ToString("f3")); //#.### 
                tKey.inTangent = float.Parse(tKey.inTangent.ToString("f3")); 
                tKey.outTangent = float.Parse(tKey.outTangent.ToString("f3")); 
                tKeyFrameArr[j] = tKey; 
            } 
            tCurveData.curve.keys = tKeyFrameArr; 
            _clip.SetCurve(tCurveData.path, tCurveData.type, tCurveData.propertyName, tCurveData.curve); 
        } 
    }
    

    在做完这两步后,几个关键的值确实要小了,文件大小也减小了一些。

    image.png image.png

    取了一个动画片段的压缩前后的数据(如上两图的对比,上面是压缩前,下面是压缩后),可以看到确有改善。

    实际运用中会有几个关键的点,状态机中的动画与motion指定的动画的名字上可能不同,所以直接从controller中获取animationClips会有两个问题:

    1. 名字不匹配,那么在重新绑定的时候可能绑定不上;

    2. 直接new操作得到的AnimationClip即使用了压缩的操作,有可能得到的也要比直接的FBX文件中的文件要大。

    然后试着直接从FBX文件中提出.anim文件(Unity中直接操作的快捷键是Ctrl+D),然后单独压缩,会发现实际确实会小很多,所以,解决思路就有了。

    static void ExtractAnimationAndSave(string path)
    {
        var controller = AssetDatabase.LoadAssetAtPath<AnimatorController>(path);
        if (controller == null || controller.layers == null)
        {
            return;
        }
    
        var fileInfo = new FileInfo(path);
        string folder = fileInfo.DirectoryName;
    
        var oldClipMap = new Dictionary<string, string>();
    
        // 提取状态机中每个状态的motion
        for (var i = 0; i < controller.layers.Length; ++i)
        {
            var stateMachine = controller.layers[layerIndex].stateMachine;
            if(stateMachine == null)
            {
                continue;
            }
            var childStates = animatorStateMachine.states;
            if(childStates == null)
            {
                continue;
            }
    
            for(var index = 0; index < childStates.Length; ++index)
            {
                var motion = childStates[childStateIndex].state.motion;
                if(motion == null)
                {
                    continue;
                }
    
                if (motion is BlendTree)
                {  
                    var motionBlendTree = motion as BlendTree;
                    if(motionBlendTree == null || motionBlendTree.children == null)
                    {
                        continue;
                    }
    
                    foreach(var child in motionBlendTree.children)
                    {
                        oldClipMap.Add(child.motion.name, child.motion.name);
                    }
                }
                else
                {
                    oldClipMap.Add(childStates[childStateIndex].state.name, motion.name);
                }
            }
        }
        var newClipMap = new Dictionary<string, AnimationClip>();
    
        // 从.FBX文件中提取AnimationClip文件
        // 参考https://www.cnblogs.com/jietian331/p/7264367.html)
        foreach (var clip in oldClipMap)
        {Path.Combine(path1, path2)
            string fbxPath = $"{folder.Replace('\\', '/')}/{controller.name + "@" + clip.Value + ".FBX"}";
            fbxPath = Path.Combine("Assets", fbxPath.Substring(Application.dataPath.Length + 1)).Replace('\\', '/');
    
            AnimationClip src = AssetDatabase.LoadAssetAtPath<AnimationClip>(fbxPath);
            AnimationClip newClip = new AnimationClip();
            EditorUtility.CopySerialized(src, newClip);
    
            string animPath = $"{folder.Replace('\\', '/')}/{newClip.name + ".anim"}";
            animPath = Path.Combine("Assets", animPath.Substring(Application.dataPath.Length + 1)).Replace('\\', '/');
    
            if (!File.Exists(animPath))
            {
                AssetDatabase.CreateAsset(newClip, animPath);
                AnimationCompress.CompressAnimationiClip(newClip);
                AssetDatabase.SaveAssets();//保存修改
                newClipMap.Add(clip.Key, newClip);
             }
         }
    
          if (newClipMap.Count > 0)
          {
              // 重新绑定
              RebindAnimatorController(controller, newClipMap);
          }
    
           AssetDatabase.SaveAssets();//保存修改
    }
    

    相关文章

      网友评论

          本文标题:Unity中动画文件压缩优化

          本文链接:https://www.haomeiwen.com/subject/ehyjzctx.html