UE 中脚部 IK 使用总结
UE 中脚部 IK 使用总结
本文主要关于如何在 UE 中配置 Foot IK。其背后的算法、原理因为涉及内容较多,后面会单独另外写一篇。
UE4 中 通过 Two Bone IK 进行 脚部 IK 的配置
UE4 的动画蓝图中有多个专门给 IK 用的动画节点,我们比较常用的 IK 动画节点是 Two Bone IK。下面内容主要关于如何使用 Two Bone IK 动画节点来实现基本的脚部 IK。此处不包含后期4.26新引入的 Control Rig 内容(避免和后面 UE5 部分重复),只纯粹通过动画蓝图动画节点 Two Bone IK 实现。
Two Bone IK 只适合比较简单的骨骼脚部骨骼结构(即只有脚踝、膝盖、大腿3个节点),不适合比较复杂的多个骨骼组成的情况(例如大腿-大腿part1-大腿part2-大腿part3-膝盖-膝盖part1-膝盖part2-膝盖part3-脚踝,这类构造)。如果遇到到需要在复杂脚部骨骼上使用的情况,那么就需要在 UE 中先自行创建虚拟骨骼,将结构简化成大腿-膝盖-脚踝的结构,然后每帧复制原模型骨骼的旋转值到虚拟骨骼,接着通过 Two Bone IK 对虚拟骨骼进行 IK 计算,计算好之后再把虚拟骨骼的位置复制回模型对应的骨骼上。这个过程会比较繁琐,而且容易写错。
接下来我们看一个用 Two Bone IK 节点实现 IK 的例子。这个示例使用了官方第三人称 demo 来二次开发。运行 demo,可以看到原版 UE4 官方第三人称 demo 没有设置脚部 IK :
小白人在楼梯这类地方脚可能会悬空,而不是身体向下移动,让两只脚都踏在台阶上。
接下来我们在动画蓝图中引入 Two Bone IK 节点并指定好参数即可配置好 Two Bone IK。我们先看看Two Bone IK 节点暴露出来可以配置的参数:
- IKBone: 就是要 IK 处理的目标骨骼,通常是骨链末端的骨骼,例如脚踝或者手腕之类。这里传入骨骼名字即可;
- Allow Stretching:允许骨骼被拉伸,这个选项如果勾选上,在 IK 目标点太远的时候,会允许骨骼被拉伸,从而保证目标点能够到达(有点类似橡筋人的效果);
- Maintain Effector Rel Rot: 如果勾选了 Take Rotation from Effector Space 那么这里的设置会无效。主要用来保证被 IK 作用的末端骨骼能够保持在原来的局部旋转角度。通常不会勾选;
- Allow Twist: 是否允许关节调整位置(通常都勾上,不会改),不允许的话就需要修改
Twist Axis
, 指定关节可以调整的轴。例如如果Twist Axis
中只有X
轴为 1 ,那么关节只可以在X
轴(这个模型膝盖关节的X
轴对应上下)上进行调整(UE中对应的是)。如果设置的Twist Axis
有问题的话可能会出现以下效果:
上图便是只允许在Y
轴上调整,而膝盖关节的Y
轴对应的是前后,因此关节只能够前后移动而不被左右移动,导致与脚踝脱节; - Enable Debug Draw: debug 用,勾选上可以看到 Effector 位置和 Joint Target 设置的位置,主要调试用;
- Effector Loaction Space: Effector 使用的空间,例如是 Component Space 还是 World Space 等;
- Take Rotation from Effector Space: 如果勾选上此选型,那么末端骨骼的旋转值会从 Effector 取;
- Effector Target: Effector 的作用目标;
- Effector Location: Effector 的位置,其实就是末端骨骼要运动到的目标位置;
- Joint Target Location Space: Joint Target 使用的空间,例如是 Component Space 还是 World Space 等;
- Joint Target: Joint Target 作用目标,用来指定某个骨骼作为关节、控制 IK Bone 的父骨骼;
- Joint Target Location: Joint Target 倾向运动的目标位置,在膝盖往外拐或者内拐的时候修正膝盖朝向用;
未修正:
修正后:
重点其实是在 Effector 和 Joint Target 的设置上。Two Bone IK 节点封装得比较好,只需要设定好参数,传入 Effector Target 目标位置就可以实现 脚部 IK。
配置脚部 IK
首先在动画蓝图中创建两个 Two Bone IK 动画节点,并分别对左右脚进行配置,同时对 Pelvis 骨骼进行位置调整,即对模型整体位置进行调整:
其中 Two Bone IK 动画节点参数配置如下图所示:
对 Pelvis 骨骼的设置如下图所示:
另外,之所以时 Pelvis 是因为 Pelvis 是除了 Root 骨骼之外的最顶层骨骼,相当于对整体骨骼进行一个偏移:
我们先暂时忽略掉前面几个Offset
变量在哪里更新的问题,等等再回到这部分。接下来我们去到小白人的角色蓝图,并制作下面的蓝图函数:
这个函数主要用处就是根据给定的骨骼(虽然函数名字叫做 Get Socket Location
,但是实际上在 UE 里面没区分这么严格,骨骼也可以是 Socket)和给定的检测距离 \(d\),在给定骨骼的位置上方 \(\frac{d}{2}\) 高度开始,向地板方向进行射线检测,检测总长度为给定的检测距离 \(d\)。最后通过射线检测到的碰撞位置(即射线与地面的交点)\(\overrightarrow{r_{\mathrm{hit}}}\)、射线末端位置 \(\overrightarrow{r_{\mathrm{end}}}\)、射线长度 \(d\),计算出碰撞位置到射线末端的长度 \(d_{2}\),由 \(\frac{d}{2} - d_2\) 得出脚到地面的距离(其实是胶囊体底部到地面的距离,但是通常我们会保证模型默认姿势时脚就在胶囊体底部位置上,所以最终计算结果是一样的)。
下图是站在地面的情况,此时末端到地面长度与射线长度的一半,即 \(\frac{d}{2}\), 一致,所以不需要偏移:
在一只脚在高处一只脚在低处的时候可以看到,较低处的脚会需要偏移(不偏移的话会浮在空中,就像前面没有添加IK时候的那样),偏移量就靠我们前面的函数计算得出:
上图就是IK前的状态,我们计算得出偏移量之后对根节点往下偏移(否则左脚无法站在下面的地面上),同时将左脚上的 IK Effector 移动到较低的地面上。
最终得到:
其实上面缺了一个步骤,毕竟上面只是制作了计算偏移量的函数,还没有调用。因此我们需要在角色蓝图的 Tick 中进行调用:
上图的流程:
- 调用了我们先前定义的射线检测函数,计算出脚部偏移量,记录到变量中;
- 比较左脚与右脚的偏移量,选择最小值作为 Pelvis 骨骼偏移量(选最小值也是因为前面实际上写成了\(d_2 - \frac{d}{2}\),最后得到的是负数,所以需要比较一下选最小值,实际上就是选距离最大的);
随后,我们回到动画蓝图,我们将会在动画蓝图的 Update 函数中读取上面角色蓝图里面记录的变量:
这里我们封装读取变量的部分成一个名为 UpdateOffset
的函数,其定义如下:
这里要和HipOffset
相减是我们动画蓝图里面会用HipOffset
来调整Pelvis
的高度,因此需要剪掉这部分避免重复偏移。
最后动画蓝图运行的时候根据计算出的偏移量进行偏移:
最终实现效果:
可以看到已经没有出现前面的脚浮空的问题了。
没有 IK 骨骼的处理
没有 IK 骨骼的话得要手动创建虚拟骨骼,简化模型骨骼。动画蓝图流程编程:
- 先复制原骨骼的位置、旋转角,并赋值给虚拟骨骼;
- 对虚拟骨骼进行
Two Bone IK
处理,移动到目标位置; - 将虚拟骨骼更新后的目标位置、旋转值重新复制回去对应的骨骼上;
其他部分,计算距离等步骤和上面一致。
UE5 中的 IK 使用(Control Rig 实现)
UE4.26 中引入了 Control Rig,但是实际上到 UE5.0 才算稳定下来。所以我将 Control Rig 设置 IK 的部分放在这里,并且是在 UE5 项目中实现。
用 Contro Rig 实现的另一个原因是,UE 官方推荐脚部 IK 之类的动画优化都放在 Control Rig 中进行处理。这样动画蓝图可以专注动画切换逻辑处理,而不用把动画优化和切换混在一起导致动画逻辑混乱。
Control Rig 简介
官方介绍:
Control Rig 是基于节点的操控系统,设计用于为操控者和动画师提供多种工具,通过对美术师友好的界面来创建灵活、动态和程序性的角色。与蓝图不同,Control Rig 使用称为 RigVM 的自有轻量级 VM 提供高效的姿势计算。用户可将称为 Rig Units 的节点与 Control Rig 图连接在一起,创造运行时间和动画 rig。
总而言之,就是用来方便操作、控制动画的一套操控系统:
MetaHuman 项目中就通过 Control Rig 实现了复杂的表情系统:
此外,Control Rig 还可以用于在运行时优化动画,例如加入脚部、手部 IK 等功能。我们主要关注如何用 Control Rig 实现 IK 功能。
UE5 官方 Demo 中的 IK
下面主要解析一下官方 Demo 实现的 IK,这里的 Demo 是 UE5 内置的第三人称模版 Demo。
首先我们看看第三人称模板中实现的脚部 IK 效果:
可以看到看起来实现还是不错的。
首先我们看看 Control Rig 的总览(可能看不太清楚,不过没有关系,我会在后面详细介绍每一步做了什么):
其实就分了5个步骤:
- 首先判断是否进行 IK (因为有时候会关闭 IK,例如跳跃的时候),如果进行 IK 的话会在双脚(通常是脚踝处)进行射线检测(虽然实际调用的函数叫做 Sphere Trace,不过还是和射线检测差不多的东西),并记录下脚到地面的偏差值/距离;
- 对脚部的当前 Z 偏差值(这是一个独立的变量,不是脚部的Z轴的值)进行插值,使之逼近目标偏差值;
- 对 Pelvis 处(通常是臀部位置的骨骼,差不多在骨盆中心的位置)的当前 Z 偏差值也进行插值,使之逼近最低处脚部的目标偏差值,这是为了适配一只脚在高处一只脚在低处的情况,这样可以保证低处的脚能站在地面上而不会因为脚不够长而悬在空中;
- 将2、3步计算出来的当前 Z 偏差值添加到 Pelvis 骨骼、双脚对应的 IK 骨骼的Z轴上;
- 使用 Full Body IK节点,设定好 Effector 作用在双脚对应的骨骼上(如小白人模型的
foot_l
和foot_r
),并将双脚IK骨骼的值复制给Effector,使之计算出双脚骨骼及父骨骼的位置,实现脚自适应高度,站在地面上的效果;
接下来我们分步骤进行分析。
第一步 检测脚到地面距离以及地面的倾斜角度
先看总览:
首先判断是否要进行 IK ,这里判断依据的变量ShouldDoIKTrace
是暴露出去的,可以在动画蓝图外面控制。如果不进行 IK 的话会把双脚的 Z 方向 Offset 设为0,即不需要改变脚部高度。
如果进行 IK,那么会调用 FootTrace
函数来获取脚到地面的距离,我们看下这个函数的实现。
可以看到函数所做的事情:
- 获取传入骨骼的 XYZ 坐标,并根据坐标、添加的偏移量设置射线参数。偏移主要是在 Y 轴上偏移了 5 个单位,即前进方向上偏移 5 个单位,从脚踝处移动到脚部中间;射线起始点的 Z 轴设定为脚踝 Z 轴值基础上,向上方偏移 30 个单位,而终点则设定为在脚踝 Z 轴下方 50 个单位,这样设置可以保证射线检测能检测到在脚上方、下方的障碍物;
- 进行射线检测,得到射线与地面/障碍物发生碰撞的位置以及碰撞地方的法线值(这里法线值主要方便后面将脚部适配斜面,不过官方模板并没有适配倾斜角);
射线路径如下图所示:
第二步 插值
我们分开真正的目标值(第一步设置的)与当前脚部的偏移值,用Alpha Interpolate
函数进行插值计算出脚部新的偏移值,后面再把计算出来的新偏移值设置到脚部上。这一步主要是平滑动画用,避免脚部位置突变。
第三步 设置腰部偏移
取测量出的两脚到地面的距离,取最大距离作为腰部的偏移值。这么做是为了能够让模型总体向下移动,从而保证位置较低的脚能够站在地面上:
这里之所以用Less
来进行判断,是因为我们前面FootTrace
函数中返回的是射线与物品碰撞点的坐标,而我们直接把碰撞点世界坐标 Z 轴的值设置为偏移量,因此 Z 越小,就代表脚到地面越低,脚离地面的距离越可能大(因为实际上这里我们没有计算距离,所以只是可能):
如果不取距离最大的值来设置模型的高度偏移量,那么很可能因为脚不够长而导致脚必须通过拉伸才能够被放置在地面上。
另外,上面的腰部指 Pelvis
,即模型的第二层骨骼:
设置 Pelvis
骨骼的位置能够影响整个模型的位置。
第四步 更新骨骼位置
这一步更新双脚对应的 IK 骨骼的位置,以及 Pelvis
骨骼位置。这里只是简单的在世界空间中,Z 轴上添加了偏移量。之所以不直接更新双脚位置是因为如果需要调整双脚的位置,还需要顺带更新双脚父骨骼的位置、旋转值,即必须借助 IK 算法来进行更新。这里 IK 骨骼其实相当于一个临时变量,用来暂存更新后的位置数据。
第五步 用 IK 算法设置脚部位置
这一步读取上一步 IK 骨骼更新后的位置数据,并设置给双脚骨骼 Effector 目标位置,让 IK 算法依据目标位置反推父骨骼位置、角度,让双脚移动到目标位置上。
这样就基本实现脚部 IK 了,可以看到角色双脚可以适配各类高低地形,不会出现浮空的现象:
但是还有点瑕疵,在斜面上的时候脚会有一部分穿入地面,而且也不能够贴合地面:
如果要修复这个问题,就需要利用第二步射线检测到的斜面倾斜角度,修正脚部角度,使得脚部贴合地面。
最后,记得在动画蓝图加上 Control Rig
节点,让动画生效即可:
(忽略掉 Control Rig
后面一系列节点,那部分是其他的优化,与脚部 IK 无关)。
Control Rig
节点记得配置属性这里,指定好对应的 Control Rig Class
:
参考资料
- UE4中的TwoBoneIK
- UE4 脚部IK Foot Placement 的实现:UE4 中实现脚部 IK 部分的蓝图来自此文章,略有修改