Unity Animation Rigging 程序化行走
为什么要程序化行走
制作Unity行走时动画时,如果仅仅使用传统的动画系统,往往无法做到与地形完美的贴合,比如上坡时,脚下踩到石头时,效果就不太好。此时就可以考虑程序化行走啦。
效果视频
Unity Animation Rigging 程序化行走
原理
首先得明白IK,即反向运动学,其实就是根据目标的位置,推算骨骼系统各个关节的运动位置和朝向,以达到尽量靠近目标的目的。比如要拿起桌子上的苹果,人的大脑会瞬间进行计算,控制肩膀、胳膊肘、手腕等关键进行运动,最终使手触达苹果,这个过程就是IK。然后,程序化行走就是基于IK的,这需要逆向思考一下,其实程序化行走,并不是腿把身体支撑了起来,而实际上,我们控制的是身体,然后根据当前的坐标位置,判断跟身体匹配的下一步的落脚点,最后利用IK去反向计算腿部的关节。

最简单的情况:以身体坐标为参考,针对每个腿,赋予一个恰当的偏移量(上图红球位置),然后朝地面发射一根射线,用来检测落脚点,然后就能根据hit.point知道落脚点的地面高度了,然后将腿部的IK目标点设置为该点,剩下的就是交给Unity引擎了,unity会根据目标点位置,还有IK的各类约束(比如有的关节会约束旋转的角度,比如人的膝盖,永远不能向前打弯),去自动计算腿部的姿态。
然后就简单了:
/* --------------------
* 此代码挂在脚上
* --------------------*/
private void Update()
{
// lerp表示上一步落脚点到下一步落脚点的行进进度(0-1)
if (lerp < 1)
{
lerp += walkerBody.StepSpeed * Time.deltaTime;
if (lerp >= 1)
{
// 如果已经踩到新的落脚点
transform.position = targetPos;
oldPosition = targetPos;
walkerBody.OnStepDone(this);
}
else
{
// 正在迈步,通过高度上增加Sin函数,则可以让脚步的位置有弧线变化。
Vector3 pos = Vector3.Lerp(oldPosition, targetPos, lerp);
pos.y += Mathf.Sin(lerp * Mathf.PI) * walkerBody.StepHight;
transform.position = pos;
}
}
else
{
// 不管身体位置如何变化,IK目标点总是设置到落脚点上
transform.position = oldPosition;
// 判断身体的位置移动,是否超过步长,超过就要迈步。
if (Physics.Raycast(walkerBody.transform.position + stepOffset, Vector3.down, out RaycastHit hit,
stepOffset.y * 2, walkerBody.GroundLayerMask))
{
// 左脚和右脚不能同时迈步,这里判断一下不能同时迈步的其他脚是否正在迈步。
if (CantSimultaneous != null && CantSimultaneous.Any(other => other.IsWalking))
return;
if (Vector3.Distance(hit.point, oldPosition) > walkerBody.StepDistance)
{
lerp = 0;
targetPos = hit.point;
}
}
}
}
上面的代码是根据官方例子修改而来,然而有些不太完美的地方在于,**迈步动作太被动了。**往往身体都移动了半个步长了,脚才开始迈步,好像腿被打断了拉在后面一样。

后来,在落脚点检测的时候,又增加了行进方向上的偏移,相当于身体迈步前,就朝身体运动的方向提前一点判断落脚点,然后整个动画就很舒服了。并且把迈步的机制,从“脚”移动到了“身体”。
/* --------------------
* 此代码挂在身体上
* --------------------*/
private void Update()
{
Vector3 dir = new(Input.GetAxis("Vertical"), 0, -Input.GetAxis("Horizontal"));
if (dir.sqrMagnitude > 0.25f)
{
Vector3 realdir = transform.TransformDirection(dir).normalized;
Controller.SimpleMove(realdir * MoveSpeed);
if (IsMoving)
{
Vector3 offset = transform.position - oldPosition;
if (offset.magnitude > StepDistance)
NextStep(realdir);
}
else
{
IsMoving = true;
NextStep(realdir);
}
}
else
{
IsMoving = false;
}
}
最后再来个2足的机器人效果:
Unity Animation Rigging 程序化行走
继续完善
其实可以继续完善的地方还有很多,比如在传统行走动画的基础上,增加IK约束,预判障碍物形状,使用不同的翻越动画越过障碍等。
本文介绍如何使用Unity结合IK实现程序化行走,使角色动画更好地适应地形变化,包括上坡、踩石等复杂情况。通过射线检测和IK计算,确保角色行走时的自然流畅。
1192

被折叠的 条评论
为什么被折叠?



