Unity 动画融合 IK MatchTarget 导播

认识未深,记录备忘

动画融合

Stealth秘密行动 14-17

新建状态机

面板上的Motion

//Motion运动
//Locomotion,运动,自己的命名
//Loco,机车
//Blend,混合
在这里插入图片描述

与普通动画在面板上的区别

//普通动画的Motion是一个动画Clip
在这里插入图片描述

新建行为树

//双击点进去
在这里插入图片描述

添加动画

//点击节点
//点击右边的先小圈圈,进行动画的添加
//动画项不够,就点击下面的“+”
在这里插入图片描述

(1D例子) Speed的大小控制由走到跑

//右下角可以拖其他模型
在这里插入图片描述

效果

//gif卡3M大小上传真不容易
在这里插入图片描述

可以拖其他模型到右下角的窗口

在这里插入图片描述

(2D例子)

unity TimeLine应用教程 酷炫开场动画 23-31
//cartesian,笛卡尔
//1、选择一个2D(哪个2D都试一试,主要出效果),选参数(Horizontal表示水平/左右,Vertical表示垂直/前后)
//2、随便选(可能就是角速度控制左右可以参考,其他的不知道要参考哪些要素),只要出3的效果
在这里插入图片描述

切/调整动画

一般是一个模型的所有动画都放在一个总Clip中,需要什么状态的Clip,已切好或自己切。
//1、切图看循环播放时是否连贯
//2、可以旋转,打钩(比如Idle/Walk/RunForward,就是不能旋转;相反地,RunLeft/RunRight没打钩·,可以旋转)
//3、Y轴没影响,都打钩,表示不会在Y(高度上变化)
//4、边移动边旋转,就是位移靠动画(以前不考就是靠角色控制器的SimpleMove()、MoveForward()之类的)
//5、镜像,省功夫的,比如RunRight是RunLeft的镜像,设置数据都是抄RunLeft的
//6、比如RunLeft/RunRight,Y角速度变化明显,所以在行为树中,适合用角速度来控制RunLeft/RunRight(详细有以下的“角速度”)
在这里插入图片描述

角速度

//角速度对转向的影响比较大
//转弯靠转身,而不是“螃蟹”横着走
在这里插入图片描述

效果

在这里插入图片描述

(问题) Animator打开为空

重启

IK

抗木头

unity TimeLine应用教程 酷炫开场动画 43-47

FixAnimatorIKPositionAndRotation(骨骼部位, 具体位置, 权重)【自定义的函数】

    [Tooltip("肩膀上的木头,一开始不激活")] public GameObject wood;
    [Tooltip("模型中左手腕处")] public Transform leftHand;
    [Tooltip("模型中右手腕处")] public Transform rightHand;
    //
    private void OnTriggerEnter(Collider other)//接触木头
    {
        if (other.tag == "Log")
        {
            Destroy(other.gameObject);
            print("碰撞");
            CarryWood();
        }
    }
    private void CarryWood()//扛木头
    {
        wood.SetActive(true);
        animator.SetBool(willHoldLogID,true);
    }
    private void OnAnimatorIK(int layerIndex)//每帧调用,需要层启用IK
    {
        if (layerIndex == 1)//对应HoldLog层
        {
            int weight = animator.GetBool(willHoldLogID) == true ? 1:0;//willHoldLogID的值

            FixAnimatorIKPositionAndRotation(AvatarIKGoal.LeftHand,leftHand, weight);
            FixAnimatorIKPositionAndRotation(AvatarIKGoal.RightHand,rightHand, weight);
        }
    }
    private void FixAnimatorIKPositionAndRotation(AvatarIKGoal target, Transform match, int weight)//使用match的位置角度来调整target
    {
        animator.SetIKPosition(target, match.position);//设置位置
        animator.SetIKRotation(target, match.rotation);
        animator.SetIKPositionWeight(target, weight);//设置优先级
        animator.SetIKRotationWeight(target, weight);
    }

第一个参数 骨骼部位

AvatarIKGoal.LeftHand
AvatarIKGoal.RightHand
意思是,这一层的状态机只动用到左右手。其他部分不归它管
在这里插入图片描述

第二个参数,位置LeftHand/RightHand

//具体操作是,在木头下新建两个空节点,来存储“抗木头”时左右手的Transform
//旋转手,使之贴合木头达到效果
//把此时左右手的Transform赋值给木头下的两个空节点。左右手复位
在这里插入图片描述

第三个参数 IK认骨骼的位置还是target(自己设置)的位置

//原理不清楚,反正不都设为1(认target的位置),都会出现位置错误
在这里插入图片描述

方法参数对比

Animator.SetIKPositionWeight
在这里插入图片描述

目标匹配 MatchTarget

翻墙

//绿球是以下代码生成的

        animator.MatchTarget(matchTarget,
            Quaternion.identity,
            avatarTarget,
            new MatchTargetWeightMask(matchTargetWeightMask, 0),
            startTime,
            endTime
        );

在这里插入图片描述

    private void Vault()//腾跃,尝试过和Slide重构复用,太麻烦
    {
        //1、播放动画
        //速度>3 && 是 LocalMotion行为树

            //射线检测
            float testDistance = 4f;//检测距离
            float vaultDistance = 3f;//起跳距离
            bool willVault = false;//是否要进行翻墙

            //rayPos,direction,射线,长度
            bool isHit = Physics.Raycast(transform.position+Vector3.up*0.3f, transform.forward, out RaycastHit hit, testDistance);
            if (isHit && hit.collider.tag == "Obstacle")//障碍物是墙
            {
                if (hit.distance > vaultDistance)//
                {
                    willVault = true;
                    //
                    Vector3 point = hit.point;
                    point.y = hit.collider.transform.position.y + hit.collider.bounds.size.y;//位置加自身高度
                    matchTarget = point;//得到着手点
                    matchTarget.y +=matchTargetOffsetY;
                }
            }          
            animator.SetBool(willVaultID, willVault);
        

        //2、MatchTarget
        //有一个状态叫ClimbOver && 在翻墙中, 不在状态切换过程中(差值)
        if (animator.GetCurrentAnimatorStateInfo(0).IsName("ClimbOver") && animator.IsInTransition(0) == false)
        {
            //1、MatchTarget
            float startTime = 0.3f;
            float endTime = 0.4f;
            MatchTarget(matchTarget, AvatarTarget.LeftHand, Vector3.one, startTime, endTime);
        }
    }
        void MatchTarget(Vector3 matchTarget,AvatarTarget avatarTarget, Vector3 matchTargetWeightMask, float startTime, float endTime)
    {
        //动画在(startTime,endTime)时
        animator.MatchTarget(matchTarget,
            Quaternion.identity,
            avatarTarget,
            new MatchTargetWeightMask(matchTargetWeightMask, 0),
            startTime,
            endTime
        );
    }

滑地

//我主要调endTime
//视频matchTarget = hit.point+transform.forward * 2(越大越远,视频看效果时设为10,滑地了很远)
//matchTarget决定改动画在(startTime, endTime)期内,整个模型会向前移动多远
在这里插入图片描述

    void Slide()//滑地
    {
        //1、播放动画
        //速度>3 && 是 LocalMotion行为树
        if (animator.GetFloat(verticalID) > runSpeed && animator.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
        {
            //射线检测
            float testDistance = 4f;//检测距离
            float slideDistance = 2f;//滑地距离
            bool willSlide = false;//是否要进行翻墙


            //start,direction,射线,长度
            bool isHit = Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out RaycastHit hit, testDistance);

            if (isHit && hit.collider.tag == "Obstacle")//障碍物是墙
            {
                if (hit.distance > slideDistance)//起跳距离
                {
                    willSlide = true;

                    //设置match
                    Vector3 point = hit.point;
                    point.y = 0;//滑行不影响高度
                    point = point + transform.forward*10;
                    matchTarget = point;//滑行个2米
                }                  
            }
            animator.SetBool(willSlideID, willSlide);
        }
          
        //
        if (animator.IsInTransition(0) == false && animator.GetCurrentAnimatorStateInfo(0).IsName("Slide"))
        {

            //1、MatchTarget
            float startTime = 0.38f;//0.17
            float endTime = 0.67f;//0.67f;//30
            //float startTime = 0.17f;//0.17
            //float endTime = 0.30f;//0.67f;//30
            MatchTarget(matchTarget, AvatarTarget.Root, new Vector3(1, 0, 1), startTime, endTime );
        }
    }
    void MatchTarget(Vector3 matchTarget,AvatarTarget avatarTarget, Vector3 matchTargetWeightMask, float startTime, float endTime)
    {
        //动画在(startTime,endTime)时
        animator.MatchTarget(matchTarget,
            Quaternion.identity,
            avatarTarget,
            new MatchTargetWeightMask(matchTargetWeightMask, 0),
            startTime,
            endTime
        );
    }

导播

public PlayableDirector director;//过场动画的相机,播放时间轴
    private void OnTriggerEnter(Collider other)//接触木头
    {
        if (other.tag == "Playable")
        {
            director.Play();//播放Timeline
        }
    }

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值