[关闭]
@Satellite-109 2020-04-02T03:14:21.000000Z 字数 4448 阅读 1317

Unity之Animator

Animator IK MatchTarget StateMachine BlendTree


StateMachine

Animator 主要通过状态机控制人物动画状态改变
Animator 编辑器各个属性如图:
Animator编辑器属性
人物遮罩
GGsa4S.jpg

属性说明
融合方式Override为覆盖,Additive为附加。附加将通过内部插值运算自动融合不同层级动画
权重权重为1时 且 融合方式为Override时,该层将覆盖底层的动画
人物遮罩人物遮罩应用于层级部分动画显示。如图,当该层(含遮罩)动画播放时,将播放双手、头部、body的动画,而处于红色的双腿动画将不会播放出来,显示别的层级的双腿动画
IK勾选IK即可通过局部带动整体的骨骼显示。IK通过Unity自带的函数进行代码控制 private void OnAnimatorIK(int layIndex) 以及 private void OnAnimatorIK() layIndex为层级下标。Base Layer为0,逐级递增

BlendTree

混合树就是将多个相似的动作混合(混合造型与时间相似的动作)
混合类型:

类型 属性
1D 使用一个参数进行混合,最好混合同个方向的动画,例如:向前走,向前跑
2D Simple Direction 混合不同方向的动画,需要有一个位于(0,0)的动画,例如:Idle
2D Freeform Direction 类似上一种,但能混合同个方向的动画,同样需要原点动画
2D Freeform Cartesian 最好混合动作没有明显朝向区别的动画,可以在x轴和y轴使用不同的定义

MatchTarget

MatchTarget 通常用于设置人物身体的位置在规定时间内到达某个某个位置。例如,用手支撑身体时的动画,把手的位置通过MatchTarget设置到物体表面,达到更好的表现效果。与IK不同的是,存在一个变化的效果,IK直接把手放置到物体表面,不存在变化的效果。

  1. if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight"))
  2. {
  3. anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
  4. anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
  5. }

说明:当动画位于第0层的 JumpHight 动画时,设置双手在 0.13s 到 0.26s 之间通过插值的方式移动到 targetLeft 和 targetRight 这两个目标点

IK

IK通过把身体位置设置到某个位置,达到更好的表现效果。例如:持枪设计时,通过把双手设置到正前方,通过双手带动整个身体动画。

  1. private void OnAnimatorIK(int layIndex)
  2. {
  3. if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh"))
  4. {
  5. anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);
  6. anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
  7. ik = false;
  8. }
  9. }

说明:ik 为bool值变量,增加对IK的控制,当为第一层,名为“IdleGrab_FrontHigh”动画时,把右手设置到特定位置 ikPos.position 。
详情可以看官网例子,Inverse Kinematics


动画的其他控制
此处输入图片的描述

Curves

Curves可以为动画添加一条曲线,并在Animator编辑器中的参数面板添加相同的参数,则在动画播放过程中,该参数由动画自动控制,我们可以通过获取该参数的值得到相应的播放进度

Event

Events则可以添加在关键帧,并在动画播放到该位置时自动调用 Object 上的 Function ,不指定 Object 则默认挂载 Animator 上的脚本


实例

  1. public class AnimController : MonoBehaviour
  2. {
  3. private int jumpUpParameter = Animator.StringToHash("JumpUp");
  4. private int jumpDownParameter = Animator.StringToHash("JumpDown");
  5. private int walkParameter = Animator.StringToHash("Walk");
  6. private int turnParameter = Animator.StringToHash("Turn");
  7. private int colliderParameter = Animator.StringToHash("Collider");
  8. private int hookParameter = Animator.StringToHash("Hook");
  9. private int pickParameter = Animator.StringToHash("Pick");
  10. private Animator anim;
  11. private bool ik =false;
  12. [HideInInspector]
  13. public Vector3 targetLeft, targetRight;
  14. public Transform ikPos;
  15. public Transform t;
  16. // Use this for initialization
  17. void Start ()
  18. {
  19. anim = this.GetComponent<Animator>();
  20. }
  21. // Update is called once per frame
  22. void Update () {
  23. if (Input.GetKeyDown(KeyCode.W))
  24. {
  25. anim.SetBool(walkParameter, true);
  26. }
  27. if (Input.GetKeyUp(KeyCode.W))
  28. {
  29. anim.SetBool(walkParameter, false);
  30. }
  31. float turn = Input.GetAxis("Horizontal");
  32. anim.SetFloat(turnParameter, turn * 54f);
  33. if (Input.GetKeyDown(KeyCode.K))
  34. {
  35. //当前处于Idle时(Turn 等于 0)
  36. if (anim.GetFloat(turnParameter) == 0)
  37. {
  38. //跳起
  39. RaycastHit hitInfo;
  40. if (Physics.Raycast(transform.position + GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y * Vector3.up,
  41. transform.forward, out hitInfo, 1))
  42. {
  43. if (hitInfo.collider.tag == "Wall")
  44. {
  45. targetLeft = hitInfo.point + (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.left);
  46. targetRight = hitInfo.point + (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.right);
  47. t.position = targetLeft;
  48. anim.SetTrigger(jumpUpParameter);
  49. }
  50. }
  51. }
  52. }
  53. CharacterControllerEnable();
  54. if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight"))
  55. {
  56. anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
  57. anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
  58. }
  59. Attack();
  60. }
  61. private void Attack()
  62. {
  63. if (Input.GetKeyDown(KeyCode.J))
  64. {
  65. anim.SetTrigger(hookParameter);
  66. }
  67. if (Input.GetKeyDown(KeyCode.I))
  68. {
  69. anim.SetTrigger(pickParameter);
  70. }
  71. }
  72. private void OnAnimatorIK(int layIndex)
  73. {
  74. if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh"))
  75. {
  76. anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);
  77. anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
  78. ik = false;
  79. }
  80. }
  81. public void SetRightHandPos()
  82. {
  83. ik = true;
  84. }
  85. private void CharacterControllerEnable()
  86. {
  87. if (anim.GetFloat(colliderParameter) > 0.5)
  88. {
  89. anim.GetComponent<CharacterController>().enabled = false;
  90. }
  91. if (anim.GetFloat(colliderParameter) < 0.5)
  92. {
  93. anim.GetComponent<CharacterController>().enabled = true;
  94. }
  95. }
  96. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注