@Satellite-109
2020-04-02T03:14:21.000000Z
字数 4448
阅读 1618
Animator IK MatchTarget StateMachine BlendTree
Animator 主要通过状态机控制人物动画状态改变
Animator 编辑器各个属性如图:
![]()
![]()
属性 说明 融合方式 Override为覆盖,Additive为附加。附加将通过内部插值运算自动融合不同层级动画 权重 权重为1时 且 融合方式为Override时,该层将覆盖底层的动画 人物遮罩 人物遮罩应用于层级部分动画显示。如图,当该层(含遮罩)动画播放时,将播放双手、头部、body的动画,而处于红色的双腿动画将不会播放出来,显示别的层级的双腿动画 IK 勾选IK即可通过局部带动整体的骨骼显示。IK通过Unity自带的函数进行代码控制 private void OnAnimatorIK(int layIndex)以及private void OnAnimatorIK()layIndex为层级下标。Base Layer为0,逐级递增
混合树就是将多个相似的动作混合(混合造型与时间相似的动作)
混合类型:
| 类型 | 属性 |
|---|---|
| 1D | 使用一个参数进行混合,最好混合同个方向的动画,例如:向前走,向前跑 |
| 2D Simple Direction | 混合不同方向的动画,需要有一个位于(0,0)的动画,例如:Idle |
| 2D Freeform Direction | 类似上一种,但能混合同个方向的动画,同样需要原点动画 |
| 2D Freeform Cartesian | 最好混合动作没有明显朝向区别的动画,可以在x轴和y轴使用不同的定义 |
MatchTarget 通常用于设置人物身体的位置在规定时间内到达某个某个位置。例如,用手支撑身体时的动画,把手的位置通过MatchTarget设置到物体表面,达到更好的表现效果。与IK不同的是,存在一个变化的效果,IK直接把手放置到物体表面,不存在变化的效果。
if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight")){anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);}
说明:当动画位于第0层的 JumpHight 动画时,设置双手在 0.13s 到 0.26s 之间通过插值的方式移动到 targetLeft 和 targetRight 这两个目标点
IK通过把身体位置设置到某个位置,达到更好的表现效果。例如:持枪设计时,通过把双手设置到正前方,通过双手带动整个身体动画。
private void OnAnimatorIK(int layIndex){if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh")){anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);ik = false;}}
说明:ik 为bool值变量,增加对IK的控制,当为第一层,名为“IdleGrab_FrontHigh”动画时,把右手设置到特定位置 ikPos.position 。
详情可以看官网例子,Inverse Kinematics
动画的其他控制
Curves
Curves可以为动画添加一条曲线,并在Animator编辑器中的参数面板添加相同的参数,则在动画播放过程中,该参数由动画自动控制,我们可以通过获取该参数的值得到相应的播放进度
Event
Events则可以添加在关键帧,并在动画播放到该位置时自动调用 Object 上的 Function ,不指定 Object 则默认挂载 Animator 上的脚本
public class AnimController : MonoBehaviour{private int jumpUpParameter = Animator.StringToHash("JumpUp");private int jumpDownParameter = Animator.StringToHash("JumpDown");private int walkParameter = Animator.StringToHash("Walk");private int turnParameter = Animator.StringToHash("Turn");private int colliderParameter = Animator.StringToHash("Collider");private int hookParameter = Animator.StringToHash("Hook");private int pickParameter = Animator.StringToHash("Pick");private Animator anim;private bool ik =false;[HideInInspector]public Vector3 targetLeft, targetRight;public Transform ikPos;public Transform t;// Use this for initializationvoid Start (){anim = this.GetComponent<Animator>();}// Update is called once per framevoid Update () {if (Input.GetKeyDown(KeyCode.W)){anim.SetBool(walkParameter, true);}if (Input.GetKeyUp(KeyCode.W)){anim.SetBool(walkParameter, false);}float turn = Input.GetAxis("Horizontal");anim.SetFloat(turnParameter, turn * 54f);if (Input.GetKeyDown(KeyCode.K)){//当前处于Idle时(Turn 等于 0)if (anim.GetFloat(turnParameter) == 0){//跳起RaycastHit hitInfo;if (Physics.Raycast(transform.position + GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y * Vector3.up,transform.forward, out hitInfo, 1)){if (hitInfo.collider.tag == "Wall"){targetLeft = hitInfo.point + (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.left);targetRight = hitInfo.point + (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.right);t.position = targetLeft;anim.SetTrigger(jumpUpParameter);}}}}CharacterControllerEnable();if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight")){anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);}Attack();}private void Attack(){if (Input.GetKeyDown(KeyCode.J)){anim.SetTrigger(hookParameter);}if (Input.GetKeyDown(KeyCode.I)){anim.SetTrigger(pickParameter);}}private void OnAnimatorIK(int layIndex){if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh")){anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);ik = false;}}public void SetRightHandPos(){ik = true;}private void CharacterControllerEnable(){if (anim.GetFloat(colliderParameter) > 0.5){anim.GetComponent<CharacterController>().enabled = false;}if (anim.GetFloat(colliderParameter) < 0.5){anim.GetComponent<CharacterController>().enabled = true;}}}