DY_M的Unity学习日记 1 ——AnimationClip的读取与代码生成

前言

作为一个“不务正业”的东川路某男子职业技术学校的大学汪(如果有幸遇到隔壁东川路某幼师学校的大佬,求带华师小龙虾!!!),平时就喜欢用Unity用Editor,Editor Window什么的工具写一些奇奇怪怪的东西,因为想要学习研究的东西网上有效的信息都不多,只能一点点看着代码提示看着各种方法的名字配着官网的API慢慢摸索,过程艰难不说还效率低下。在海澜大佬的建议下,开始在简书将学习过程中学到的东西整理一下,如果在写的过程中能帮助到别人的话,那真的是非常开心的一件事!因为是学习的整理,如果对某个东西的理解有问题的话,请大家多多指正,非常感谢!

AnimationClip是什么

它是 储存基于关键帧的动画,但是AnimationClip和KeyFrame(关键帧)并不是直接的父子关系。AnimationClip通过EditorCurveBind或者ObjectReferenceCurveBindings(下两个统称Bind)连接AnimationCurve,一个Bind对应着一个AnimationCurve,而一个AnimationCurve对应着一个KeyFrame[ ]。其中EditorCurveBind用来绑定浮点数类型字段,Position.x Rotation.x等,而ObjectReferenceCurveBinding用来绑定其他非浮点数类型的字段,如SpriteRender里面的字段。两者差别不大,结构和使用方法基本上一样,后面只讲有关EditorCurveBind的内容。

1.png

怎么获取AnimationClip里面的信息

我们通过Unity界面大概知道了AnimationClip大概包含了什么内容,现在该到我们自己领域——代码域由顶到底去探究一下他到底是怎样的一个结构。

(1)创建一个脚本作为测试,并如图创建物体,给他的Animator一个AnimatorControl,并给它添加一个Animation,如下图随意K几帧。


image.png

image.png

(2) 认识EditorCurveBinding

image.png

通过代码提示,我们可以简单发现EditorCurveBinding主要含有两个字段:path和propertyName。键入如下代码:

PS:使用OnDrawGizmos主要是因为它可以实时debug,gizmosCount是为了避免Debug过快的问题

public class AnimationLoad : MonoBehaviour
{
    public AnimationClip anim;

    public int gizmosCount = 0;


    public void OnDrawGizmos()
    {
        if (anim == null)
        {
            return;
        }
        if (gizmosCount != 20)
        {
            gizmosCount++;
            return;
        }
        else
        {
            gizmosCount = 0;

            //Coding
            
            //EditorCurveBinding[] binds = AnimationUtility.GetObjectReferenceCurveBindings(anim)
            EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
            foreach (var bind in binds)
            {
                Debug.Log("Path: "+bind.path);
                Debug.Log("Property Name: "+bind.propertyName);
            }

            //Coding
        }
    }
}
image.png

观察Console可以判断path为被控制物体相对于根物体的位置。


image.png

而propertyName为被控制组件被控制property(属性)的名字。而后面的x y z 对应这个属性内部的各个字段(一般一条Curve只能控制一个简单的值类型的字段,如:浮点数,布尔等)
Bind里面还有一个字段必须设置,Bind.type为被控制组件的类型,如果不设置set的时候会报错。

Debug.Log(“Path:”+bind.path+“,Type:”+bind.type+“,Property Name: ”+“bind.propertyName”);
后输出第一条Curve:Path: Cube ,Type:Transform, Property Name: m_LocalPosition.x 。  
就代表着这条AnimationCurve控制着Cube这个物体的Transform组件的localPosition的x这个值。
image.png

Transform相关的几个PropertyName如下

Position 位置
"m_LocalPosition"

Rotation——有三种插值类型
(1)Euler Angle    欧拉角插值
"LocalEulerAnglesRaw"
(2)Euler Angle(Quarternion) ?欧拉四元数混合类型?
 "m_LocalRotation"
(3)Quarternion    四元数插值
"m_LocalRotation"

Scale  缩放
"m_LocalScale"

其他属性可以通过类似方法通过Debug查询。

知道了Bind的功能,我们可以通过
AnimationCurve curve = AnimationUtility.GetEditorCurve(AnimationClip anim,EditorCurveBinding bind);来获取Bind所绑定的曲线。

//Coding
EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
foreach (var bind in binds)
{
    AnimationCurve curve = AnimationUtility.GetEditorCurve(anim,bind);
    Keyframe[] keys = curve.keys;
}
//Coding

通过观察AnimationCurve我们会发现,它主要管理着Keyframe[] keys, 并提供了一些处理keys的方法。我还没有看AnimationCurve其他参数的具体用法,自行研究,哈哈。

image.png

通过遍历Keys并观察Keyframe内的字段,我们会发现他的几个主要的字段。
其中:

time:(float)帧所在的时间,帧的帧号(第几帧) =  time * 每秒播放的帧数
value:   (float)  这一帧AnimationCurve所控制属性的值

//插值相关 Hermite曲线参数
inTangent:  此帧左边进入曲线的切线斜率
inWeight:   此帧左边进入曲线的切线的权重(TangentMode为Weight才有用)
outTangent:此帧右边出去曲线的切线斜率
outWeight: 此帧左边进入曲线的切线的权重(TangentMode为Weight才有用)

tangentMode:切线的模式
tangentMode.Free      自由模式,只能控制切线的斜率此时为标准hermite曲线
tangentMode.Linear    线性插值模式,此时根据相邻两帧位置线性插值,曲线与俩切线无关
tangentMode.Const     常数模式,没有插值,数值直接在帧位置突变
tangentMode.Weight   权重模式,能控制切线的斜率和权重,更方便控制曲线,切线的斜率*权重为Hermite参数

怎么代码生成AnimationClip

知道AnimationClip里面有什么东西之后,代码生成他就易如反掌了。
下面生成一段动画,动画里面的方块的Y坐标随时间呈正弦变化,插值模式为线性插值。

public void CreateAnimation(string name)
{
    //Coding
    EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
    //创建Keyframes
    Keyframe[] keys = new Keyframe[60];
    //对Keys进行赋值
    for (int i = 0; i < keys.Length; i++)
    {
        keys[i].time = i / 30f;
        keys[i].value = 2 * Mathf.Sin(2 * Mathf.PI * i / 15);
    }
    //创建曲线
    AnimationCurve curve = new AnimationCurve();
    curve.keys = keys;
    //设置模式
    for (int i = 0; i < keys.Length; i++)
    {
        AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
        AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
    }
    //创建Bind
    EditorCurveBinding bind = new EditorCurveBinding();
    bind.path = "Cude";
    bind.propertyName = "m_LocalPosition.y";
    //这个是被控制
    bind.type = typeof(Transform);

    AnimationClip animCreate = new AnimationClip();
    AnimationUtility.SetEditorCurve(animCreate, bind, curve);

    AssetDatabase.CreateAsset(animCreate, "Assets/"+name+".anim");
    //Coding
}

如果有其他需求Key的赋值处,Curve的设置处进行修改就可以了,原理基本上一样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容