学到siki学院的动画系统那一章节的IK动画Siki,顺便作点笔记。
1.什么是IK
IK(Inverse Kinematics)即反向动力学,即可以使用场景中的各种物体来控制和影响角色身体部位的运动,一般来说骨骼动画都是传统的从父节点到子节点的带动方式(即正向动力学),而IK则倒过来,由骨骼子节点带动骨骼父节点,具体情况比如人物走路踩到了石头就需要由脚的子节点来带动全身骨骼做出踩到石头的响应。(网上复制的…)
2.目标展示
我们可以看到人物背起木头时,双手和木头的贴合度非常高,不是纯粹的将树木悬置于肩上,而是与双手所绑定,接下来我们一步步还原如何实现上述过程
3.效果还原
(1).添加Log树木
素材里的Log添加到场景中,给其加上Capsule Collider组件,并且勾上Is Trigger和打上标签名Log ,方便我们之后进行触发检测。
树木旋转效果只要给其填上如下代码即可
public class RotateSelf : MonoBehaviour {
public float rotateSpeed = 90;
void Update () {
transform.Rotate(Vector3.up * rotateSpeed * Time.deltaTime, Space.World);
}
}
(2).触发检测
在我们的人物脚本中添加触发检测的代码
public GameObject unityLog;
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Log")
{
Destroy(other.gameObject);
CarryLog();
}
}
void CarryLog()
{
unityLog.SetActive(true);
}
代码中 unityLog为素材树木prefeb 将其添加到人物的模型中去,具体位置如图所示(毕竟要抗在肩上)
实际情况中记得将场景中肩上的树木SetActive为false,只有在触发检测成功的时候才会将肩上的树木显示出来。
现在的结果如下图所示:
(3).添加扛起树木的动画和骨骼遮罩AvatarMask
-
我们首先先要创建一个新的Layer层HoldLog
在其中添加一个空状态Normal和HoldLog动画 其中的转换在之后再细说 -
然后我们要添加一个AvatarMask,因为扛着木头只需要用到左右手,不需要用到身体其他部位,于是创建如下图所示的AvatarMask并添加到HoldLog层中
(4).添加动画播放的时机
-
我们首先在Base Layer层中添加一个bool变量 IsHoldLog用来控制播放的时机
-
然后我们在HoldLog层中的normal状态转换到HoldLog状态的箭头中设置IsHoldLog为true,反过来状态可以设置为false
相应的我们再添加新的代码
private int isHoldLogID = Animator.StringToHash("IsHoldLog");
//StringToHash方法可以有效避免设置变量参数时对其字符串名打错的情况
void CarryLog()
{
unityLog.SetActive(true);
anim.SetBool(isHoldLogID, true);
}
此时我们运行完结果如下图
很明显我们可以发现此时人物举起时的双手并没有和木头进行贴合,终于要讲到我们的主题了… IK动画!
(5).IK动画的设置
- 首先我们先要给木头两旁添加两个合适的点位用来之后的IK动画位置(左手和右手都要设置)
- 设置完后我们要在之前的HoldLog层中勾选上IK Pass
- 接着就是添加代码
public Transform leftHand; //就是之前我们事先设置好的木头两侧位置
public Transform rightHand;
private void OnAnimatorIK(int layerIndex)
{
if (layerIndex == 1) //只有勾选了IK Pass才有layerIndex
{
int weight = anim.GetBool(isHoldLogID) ? 1 : 0;
anim.SetIKPosition(AvatarIKGoal.LeftHand,leftHand.position);
anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, weight);//设置目标位置的权重,1表示完美匹配相当于100%
anim.SetIKRotation(AvatarIKGoal.LeftHand, leftHand.rotation);
anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, weight);
anim.SetIKPosition(AvatarIKGoal.RightHand, rightHand.position);
anim.SetIKPositionWeight(AvatarIKGoal.RightHand, weight);
anim.SetIKRotation(AvatarIKGoal.RightHand, rightHand.rotation);
anim.SetIKRotationWeight(AvatarIKGoal.RightHand, weight);
}
}
当然初次运行的时候,我们可能会发现手的位置还是没有完全匹配到木头两侧,这个时候我们就要微调之前的两个坐标位置RightHand和LeftHand
运行的时候进行移动和旋转的调试,手会同步的进行改变,记得选择好合适的位置时把Transform里面的数据复制一下(因为我们是处于运行状态时更改的数据,停止运行时数据会初始化)
好了这样我们就大功告成了,再次运行后就是我们最上方的成果的那张GIF了!
4.总结
IK动画主要关键点就是要给Animator中的需要添加IK动画的层上勾选IK Pass这样才能存在LayerMask值,然后通过方法SetIKPosition和SetIKRotation来保持需要匹配的位置和旋转角度(需要事先添加好合适的Transform),其中的SetIKPositionWeight和SetIKRotationWeight就是用来匹配契合程度的,范围是0-1,可以相当于百分比0-100%
- 源码资料链接特别感谢siki学院的网课