Unity 3d人形角色动画集、图层合并、IK反向运动学、融合树

首先,创建一个空的工程,并导入标准资源库和机器人凯莉资源包。

>>例行消除Unity标准资源包的报错

找到机器人模型

这个是它的骨骼

由于是新版unity,修改为人形

创建一个平面,导入机器人模型,然后创建一个球体

把球体绑定到头上

创建动画状态集Curve

错误步骤:

正确步骤:

错因:看错了,应该选HumannoidRun,而不是RobotBoyRun

单击选择HumanoidRun

在属性里找到曲线,添加曲线并通过曲线控制动画的播放


添加关键帧

一会儿跑慢,一会儿跑快

添加两个曲线,用这两个曲线获取参数,一个控制泡泡的大小,一个控制泡泡的颜色

若这两个曲线未添加,则不会有任何变化的效果

添加两个参数

将编辑好的动画状态集绑定到机器人上

这样机器人就跑起来了

如果想让机器人在原地运动,取消应用根运动即可

效果

附:

创建一个脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Curve : MonoBehaviour
{
    public GameObject bubble;
    Vector3 originalScale;//设定初始泡泡大小
    private Color originalColor;//设定初始颜色
    Animator anim;//先定义一个动画器对象

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();//获取动画组件
        originalScale = bubble.transform.localScale;
        originalColor = bubble.GetComponent<Renderer>().material.color;
    }

    // Update is called once per frame
    void Update()
    {
        float curve1 = anim.GetFloat("Curve1")*5;//通过调用动画对象的GetFloat函数来获取值,来修改泡泡的大小
        float curve2 = anim.GetFloat("Curve2");///通过调用动画对象的GetFloat函数来获取值,来修改泡泡的颜色
        bubble.transform.localScale = new Vector3(originalScale.x + curve1, originalScale.y + curve1, originalScale.z + curve1);//根据走路节奏调整泡泡大小,让其或大或小
        bubble.GetComponent<Renderer>().material.color = new Color(originalColor.r* 100 * curve2, 0f, 0f, 0.2f);//调用对象的组件直接修改颜色
    }
}

绑定到机器人上,并指定bubble为Sphere

效果

机器人边跑边吹泡泡,泡泡的大小和颜色随着跑步的节奏改变

附:

一定要记得随时保存场景

场景另存为场景1,再另存为场景2,在场景2中操作

取消泡泡

然后移除Curve脚本

创建一个动画状态集Layer

效果

机器人走了起来

创建一个图层

调整权重,同时执行两个动画

边走路边胳膊举起

上下半身动作分离

创建一个遮罩

下半身遮罩

下半身

上半身

效果

上半身挥手(起跳),下半身跑步

存在问题

不能循环播放动画

设置动画循环播放的方法

添加自循环,条件参数为loop,ture时循环

创建脚本

实现点击鼠标左键,让机器人循环抬手,点击右键则始终不抬手

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Layer : MonoBehaviour
{
    public float speed = 1f;
    private Animator anim;

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButton(0))
        {
            float w=anim.GetLayerWeight(1) > 1 ? 1: anim.GetLayerWeight(1) + speed * Time.deltaTime;
            anim.SetLayerWeight(1, w);
        }

        if (Input.GetMouseButton(1))
        {
            float w = anim.GetLayerWeight(1) > 0 ? 0 : anim.GetLayerWeight(1) + speed * Time.deltaTime;
            anim.SetLayerWeight(1, w);
        }
    }
}

IK 反向运动学(注视动画)

知道末端节点(手)的位置,怎么通过反向的演算,知道其他节点(身体)的位置

比如眼睛看一个地方,手要动,头要动,还要弯腰

创建一个动画状态集

效果

人晃了起来

勾选IK处理,图层就支持IK反向动力学计算

创建一个脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IKLook : MonoBehaviour
{
    Animator anim;//要用动画组件

    Ray ray;//定义射线
    RaycastHit raycastHit;//射线和地面有交叉,要定义一个射线相交的变量,就是一个注视点

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();//获取组件
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnAnimatorIK(int layerIndex)//反向动力学计算代码不在update,而是专门有一个函数
    {
        //生成一个物理射线,把它与地面相交的点作为注视点
        ray = Camera.main.ScreenPointToRay(Input.mousePosition);//发射向鼠标指向的位置

        if(Physics.Raycast(ray,out raycastHit))//调用物理引擎的Raycast函数判断射线有没有相交
        {
            Vector3 target = raycastHit.point;//如果有相交,把相交点作为一个目标

            anim.SetLookAtPosition(target);//注视目标的函数,把地面相交的点作为注视点
            anim.SetLookAtWeight(1f, 0.5f, 0.8f, 0.9f);//设定不同节点的权重
        }
    }
}

tips

效果

鼠标指向哪个地方,机器人就看哪个地方,并且手、头、背均有牵引运动

创建一个新场景

创建一个球体,放手边

给球体创建一个动画,让球上下运动

创建一个空对象作为参照物

把参照物放在球心

然后把参照物作为机器人子物体

创建动画状态集

效果

千万不要让Unity一直播放

创建脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Animator))]//强制添加安妮梅特组件

public class IKMove : MonoBehaviour
{
    public GameObject target;//创建够的目标的变量
    public GameObject hint;//参照物

    Animator anim;
    public bool isHand = true;

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();//获取组件
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnAnimatorIK(int layerIndex)
    {
        AvatarIKGoal g = isHand ? AvatarIKGoal.RightHand : AvatarIKGoal.RightFoot;
        AvatarIKHint h = isHand ? AvatarIKHint.RightElbow : AvatarIKHint.RightKnee;

        anim.SetIKPositionWeight(g, 1f);//设置位置的权重
        anim.SetIKPosition(g, target.transform.position);//设置位置
        anim.SetIKRotationWeight(g, 1f);//设置旋转及其权重
        anim.SetIKRotation(g, target.transform.rotation);

        anim.SetIKHintPositionWeight(h, 1f);
        anim.SetIKHintPosition(h, hint.transform.position);
    }

}

绑定到机器人上并如下图设置参数

动画状态集指定IK

效果

机器人用手够这个球

取消IsHand

机器人用脚够这个球

创建一个新场景和一个状态集

创建一个融合树节点

一维运动方向

调节此处可以修改运动方式

二维运动方向

添加参数

动画集参数设定(忘记了就不会动)

创建一个脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;//跨平台输入
[RequireComponent(typeof(Animator))]//强制绑定安妮梅特组件,如果这个对象没有,那么就自动添加上
public class BlendTree : MonoBehaviour
{
    Animator anim;

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        float h = CrossPlatformInputManager.GetAxis("Horizontal");
        float v = CrossPlatformInputManager.GetAxis("Vertical");

        Vector3 moveDirection = h * Vector3.right + v * Vector3.forward;//获取运动方向矢量

        if(Input.GetKey(KeyCode.LeftShift))
        {
            moveDirection.z *= 0.5f;
        }

        float turn = moveDirection.x;
        float forward = moveDirection.z;

        anim.SetFloat("speed", forward, 0.1f, Time.deltaTime);
        anim.SetFloat("turn", turn, 0.1f, Time.deltaTime);
    }
}

效果

慢速行走,快速跑步,零速静止,左转右转动画显示正常

附: 

若忘记设定参数,改成这个代码才能动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;//跨平台输入
[RequireComponent(typeof(Animator))]//强制绑定安妮梅特组件,如果这个对象没有,那么就自动添加上
public class BlendTree : MonoBehaviour
{
    Animator anim;

    public Rigidbody rbody;//公开到显示面板
    public float speed = 30f;//速度预先定义在外部

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        float h = CrossPlatformInputManager.GetAxis("Horizontal");
        float v = CrossPlatformInputManager.GetAxis("Vertical");

        rbody.MovePosition(rbody.position + transform.right * h * Time.deltaTime * speed);//刚体左右移动
        rbody.MovePosition(rbody.position + transform.forward * v * Time.deltaTime * speed);//刚体上下移动

        Vector3 moveDirection = h * Vector3.right + v * Vector3.forward;//获取运动方向矢量

        if(Input.GetKey(KeyCode.LeftShift))
        {
            moveDirection.z *= 0.5f;
        }

        float turn = moveDirection.x;
        float forward = moveDirection.z;

        anim.SetFloat("speed", forward, 0.1f, Time.deltaTime);
        anim.SetFloat("turn", turn, 0.1f, Time.deltaTime);
    }
}

附:

Unity实验汇总

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值