Unity3d开发(9)动画模型资源导入预处理

发表于2017-11-27
评论0 4k浏览

在Unity导入资源后,我们通常需要做许多设置,这些操作通常很繁琐,并且容易出错,最好的办法是使用自动的pipline处理,因为不是项目中的每一个人都十分清楚资源的结构设计。这篇文章主要探讨如何通过自动的方式实现动画模型资源的定制处理。 

AssetPostprocessor

在Unity中,AssetPostprocessor类能够在导入资源时,或导入资源后捕获到相应的信息。

在模型(Model)导入的过程中,钩子函数的调用顺序如下:

  • OnPreporcessModel 在刚进入导入阶段前,会调用这个函数。我们能够重写ModelImporter的设置来更改导入的模型的通用信息。
  • OnAssignMaterialModel 一旦网格和材质导入,这些信息就会关联到模型上,在关联之前,会调用这个函数。因此改变模型材质通常要更改这个函数。
  • OnPostprocessGameObjectWithUserProperties关联好模型的渲染信息后,会调用这个函数来处理用户信息。
  • OnPostprocessModel 这是最后一个函数,当函数运行完,则对象创建完成。这个函数有一个参数,它是这个实例对象自己。由于GameObject是引用对象,因此改变属性的操作,例如:增加脚本,更改位置,是可以带出函数作用域,保存到最终预设中的。更多情况下,我们是要更改它的ModelImporter属性。
ModelImporter model = (ModelImporter) assetImporter;

另一方面,我们可以获取gameObject.name,并依赖某些命名规则,以对导入的资源进行分类。


实际案例

由于使用了状态机控制角色动作,有些导入的FBX动画需要更改为Loop。经统计名称中包含wait、walk、run、air、dizziness的动画需要设置为循环,依照上面的原理,实现 
代码如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class Importer : AssetPostprocessor 
{
    #region Override Methods
    void OnPostprocessModel(GameObject g)
    {
        ModelImporter model = (ModelImporter)assetImporter;
        if (model != null)
        {
            if (isLoopAnimation(g.name))
            {
                //由于我们采用动画分离的导出策略,每个fbx只有一个动画
                if (model.defaultClipAnimations.Length > 0) 
                {
                    List<ModelImporterClipAnimation> actions = new List<ModelImporterClipAnimation>();
                    ModelImporterClipAnimation anim = model.defaultClipAnimations[0];
                    anim.loopTime = true;
                    actions.Add(anim);
                    model.clipAnimations = actions.ToArray();
                }
            }
        }
    }
    #endregion
    #region Inner
    bool isLoopAnimation(string objectName)
    {
        bool res = false;
        if (objectName.Contains("wait"))
        {
            res = true;
        }
        else if (objectName.Contains("walk"))
        {
            res = true;
        }
        else if (objectName.Contains("run"))
        {
            res = true;
        }
        else if (objectName.Contains("air"))
        {
            res = true;
        }
        else if (objectName.Contains("dizziness"))
        {
            res = true;
        }
        return res;
    }
    #endregion
}

将这个文件放置在工程中,可以在导入对应资源时自动对其循环属性进行转换。

其他信息

另外我还发现一个小Bug,如果在未导入资源的情况下,拖动资源经过Scene界面,Unity会报错:

NullReferenceException: Object reference not set to an instance of an object
UnityEditor.AssetDatabase.Contains (UnityEngine.Object obj) (at C:/buildslave/unity/build/artifacts/generated/common/editor/AssetDatabaseBindings.gen.cs:39)
UnityEditor.SpriteUtility.GetSpriteFromDraggedPathsOrObjects () (at C:/buildslave/unity/build/Editor/Mono/Sprites/SpriteUtility.cs:201)
UnityEditor.SpriteUtility.OnSceneDrag (UnityEditor.SceneView sceneView) (at C:/buildslave/unity/build/Editor/Mono/Sprites/SpriteUtility.cs:46)
UnityEditor.SceneView.CallEditorDragFunctions () (at C:/buildslave/unity/build/Editor/Mono/SceneView/SceneView.cs:1773)
UnityEditor.SceneView.HandleDragging () (at C:/buildslave/unity/build/Editor/Mono/SceneView/SceneView.cs:1804)
UnityEditor.SceneView.OnGUI () (at C:/buildslave/unity/build/Editor/Mono/SceneView/SceneView.cs:1284)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)

这是由于资源还未导入到项目中,所以在AssetBase中找不到对应资源UUID,出现这个错误的版本为5.3.0。

另外在OnPostprocessModel函数中,直接更改它的name,似乎不可以改变导入资源的名字。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引