【Unity动画系统】动画层级(Animation Layer)讲解与使用

时间:2024-05-08 10:10:24

如何使用Unity的Animation Layer和Avater Mask把多个动画组合使用

想让玩家持枪行走,但是手里只有行走和持枪站立的动作。

Unity中最方便的解决办法就是使用动画层级animation layer以及替身蒙版avatar mask。

创建一个动画层级

Weight表示权重,0的话则完全不播放,1的话则会播放;

Mask为骨骼蒙版

创建一个Avatar Mask

这个Avatar只会影响选中的部分。

是人形动画则直接使用Humanoid。如果不是,可以用下面的Transform直接选择哪些骨骼节点受影响或不受影响。

Blending中Override是指将当前动画取代上面的动画,而使用一部分动画则是当前动画取代之前部分的动画;而Additive指的是将上面的动画与本身动画混合起来。

勾选后为同步,表示当前层级与哪个层级保持一致。

表示开启IK动画,这里指的是蒙层的IK。

实战:


先在层级中创建一个空状态,表示在默认情况下这一层不播放任何动画。

然后添加需要的动作。

写一个参数Rifle,然后设置其启动的值。

在代码中触发:

bool armedRifle;	//用来判断是否要抬起手

    public void GetArmedRifleInput(InputAction.CallbackContext ctx)
    {
        armedRifle = !armedRifle;	//每次都取一次反
        animator.SetBool("Rifle", armedRifle);	//然后赋值给动画
    }

利用Animation Layers中的Additive模式把多个动画混合在一起(可用来实现动画的疲劳感)

Additive将现有动画添加到现有动画上,这一层动画不会取代现有动画。

常见场景就是为角色添加疲劳感。

空状态为核心的轮辐轮毂构架(Spoke-hub distribution paradigm)来安排这一层状态机

一般动画判断在代码里不太适合直接使用字符串,包括直接在调用上和不直接使用常量一致,都应先声明变量再添加

创建第三个状态机,然后将其改为Additive

    float currentFatigue;   //现在疲劳值
    float minFatigue = 0f;  //最低疲劳值
    float maxFatigue = 10f; //最高疲劳值

    int fatigueLayerIndex;  //获取动画层级

	void Start(){
		fatigueLayerIndex = animator.GetLayerIndex("State");    //获取层级序号名字
    }

	void Update(){
        CalculateFatigue();
    }

    void CalculateFatigue()
    {
        if(currentSpeed < 1f && currentFatigue >= minFatigue)    //速度小于1,疲劳值大于等于0时,疲劳值减减
        {
            currentFatigue -= Time.deltaTime;
        }else if(currentSpeed > 2f && currentFatigue <= 10) //速度大于2,疲劳值小于等于10时,疲劳值加加
        {
            currentFatigue += Time.deltaTime;
        }
        else    //最后都不属于的返回
        {
            return;
        }
        currentFatigue = Mathf.Clamp(currentFatigue, minFatigue, maxFatigue);  //限制最小值与最大值

        animator.SetLayerWeight(fatigueLayerIndex, currentFatigue / maxFatigue);  //对疲劳权重的修改,修改的层数,修改的权重值
    }

Unity动画层级(Animation Layer)的Sync和Timing介绍

新键一个层级,有些工程中我们需要将某个层级的复制下来然后修改。

可以直接使用同步Sync,打勾后选择与哪个层级同步。

虽然同步了,但是动画内容都是空的,需要自行添加,blend tree需要选择Create new BlendTree in State。

选择受伤过后的动画加入新的混合树,同样选择以什么方向为计算。

比如打架的行走是普通走路的60%。

3.5是行走混合树的阈值,这里乘以60%然后除以现在的阈值。

新阈值3.5 * 0.6 / 1.737

代码:

    int injuredLayerIndex;  //用来保存动画层的序号

    float injuredFactor = 0.6f; //角色受伤过后移动速度受到的影响
    bool isInjured; //用来表明是否受伤

    private void Start()
    {
 		  injuredLayerIndex = animator.GetLayerIndex("injured");  //获取序号
    }

    public void GetArmedInjuredInput(InputAction.CallbackContext ctx)
    {
        isInjured = !isInjured;
        if (isInjured)
        {
            animator.SetLayerWeight(injuredLayerIndex, 1);  //如果受伤则将层数权重设置为1
        }
        else
        {
            animator.SetLayerWeight(injuredLayerIndex, 0);  //如果受伤则将层数权重设置为0
        }
    }

因为没有所以使用Jump

按下空格后

层级同步,如果动画本身长度不同步怎么办?

Unity会将短的那个动画的长度修改为被它所需要同步的层级中。

如果希望由这个层级来决定动画状态的时长?

需要勾选timing。

不过只有当层级的混合模式是override的时候才可以使用

勾选了Timing后动画状态的播放时长就由它和被它同步的层级共同决定。哪个层级的决定权更大呢?看权重,当当前层级权重为1 时,听当前层级的,权重为0时,听被同步层级的,一半的话取平均值

总结:层级同步动画必须一致,关于与谁一致,看timing与weight的设置。

使用Unity动画层级后很多动画无法正常播放?Layer优先级与Additive的工作原理

动画层级优先级越往下越高。

如果Blending是override,如果权重是1,那么会将上面的全部覆盖掉;如果是某些部位,那么完全覆盖掉当前部位的动作。

如果是Additive,它不代表会代替某些动画, 它的*的优先级表示不存在任何一个override的层级可以完全覆盖掉当前的动画。

Additive的具体行为是把当前层级所播放的动画加到之前层级的结果上去,当前这里的avatar mask表示只影响躯干的部位;

weight表示它会把本身动画以多少比例添加到之前的结果上去,0表示不添加、1表示完全添加。

比如喘气弯腰最大幅度是六十度,那么权重为1时,那么就在原有动画基础上弯腰60度;权重为0.5时,那么就在原有动画基础上弯腰30度。

当一个动画只有静止的动作(如持枪),最好使用Override,因为Additive是将动画添加到其他层级的动画结果上去,而一般静止动画除了第一帧和最后一帧,中间是没有动画的,而这时候就不可能把动画添加到原来动画上去。

按照规则合理的配置层级属性