拓冰建站拓冰建站
首页 / 资讯中心 / 正文

UE4角色脚部IK实现:从射线检测到骨盆补偿的斜坡贴合方案

1. 为什么斜坡上脚会悬空先搞清楚问题出在哪做第三人称角色控制时只要场景里出现坡道、台阶、地形起伏角色脚部就会穿帮——脚后跟陷进土里或者前脚掌悬空整个脚像踩在一块看不见的砖头上。这个问题的本质原因说穿了就一句话动画系统根本不认识你的地形。动画资源里的跑动、行走片段都是在平地状态下录制的或者说是在美术同学没有考虑地形起伏的状态下刷出来的。定点动画被播放出来时脚踝关节的位移和旋转是固定的它不会因为地面高低不同就自己调整。UE4的角色控制器CharacterMovementComponent虽然能处理胶囊体在地形上的爬坡但它只管“身体”这一坨不管脚踝以下的事。所以角色在斜坡上跑时身体贴着坡面走脚踝却还停在平地动画的状态——悬空、插地、没有旋转全来了。这里要区分清楚“位置不对”和“角度不对”两个问题。位置不对是指脚踝距离地面太高或太低解决手段一般是Two Bone IK把脚“钉”到地面上角度不对是指脚掌本身没有随坡面转动解决手段是拿脚踝下方的射线检测结果来驱动脚掌骨骼的旋转。两者必须同时做只处理一个都会继续穿帮。第二个常见的坑是很多新手会用“降低屁股高度”修改骨盆/胶囊体偏移来硬凑结果角色在平地时又变矮了或者蹲着走路。这种方法只能用于“脚没有明显悬空、只是轻微陷地和离地”的情况一旦坡度超过10度腰部和膝盖的视觉扭曲会非常明显。所以我的建议是骨盆高度统一由脚部IK的结果推出来不要在外部单独加偏移后面我会详细说怎么推。还有一个容易被忽视的点即使做了IK脚掌的旋转如果不平滑角色上下坡时会一卡一卡的尤其是从平路过渡到上坡的瞬间脚掌会“啪”一下突然转一个角度看起来像脚踝骨折了。这个问题的根源是射线检测的结果没有做插值或者插值系数选得太激进。旋转插值一定要用指数平滑不能用线性插值不然帧率高的时候会抖。再补充一个从物理系统切入的角度。很多人在做脚部贴合时会想到用PhysicalAnimation或者物理模拟器去驱动脚掌让脚“自然”贴地。但物理模拟器适合做布娃娃效果、死亡倒地这类被动表现不适合做主动控制下的精准贴合原因在于物理模拟有延迟脚掌会飘、会软而且和动画系统的Transform计算互相打架。脚部IK这种“半程序化半动画”的需求老老实实用动画蓝图里的射线IK节点反而是最稳的。2. 位置贴合和角度贴合两个目标两套算法别混在一起2.1 Two Bone IK怎么把脚“钉”到地面上UE4内置的Two Bone IK节点解决的问题是给定一个目标位置让角色腿部的两根骨骼大腿、小腿按照反向动力学解算出一个合理的弯曲角度使得脚踝关节能够到达目标点。整个解算过程是CPU上跑的纯数学不需要物理引擎介入也不消耗碰撞查询性能开销极小移动端也能用。在动画蓝图里节点选Two Bone IK三个核心参数要注意IK Foot Bone选择脚踝骨骼通常是foot_l / foot_r或者ball_l / ball_r这是要被IK驱动的关节。Effector Location脚踝最终要到达的世界空间目标点也就是射线检测打到的落点。Joint Target Location膝盖的指向参考位置。这个参数特别关键它决定膝盖是朝前弯还是朝后弯。如果不设置IK解算可能让膝盖反折角色瞬间变成X型腿或O型腿。一般做法是取大腿骨骼的位置加上角色根骨骼的Z轴方向偏移得到一个“膝盖朝前方偏下”的点。Two Bone IK的用法有个前提它只调整大腿和小腿的旋转不调整脚踝和脚掌的角度。所以你会发现即使脚踝已经落到地面上了脚掌还是平平的前脚掌翘起来或者后跟陷进去。这就是为什么单做位置贴合不够必须再套一层脚掌旋转。实际操作中还有个容易忽略的细节Two Bone IK的Effect Location不要直接取射线端点的raw值要加上脚踝到脚底的距离偏移。因为射线是从脚踝位置往下打的打到的点是脚踝正下方的地面而角色的脚踝骨骼通常在模型里离脚底有一定高度比如战靴的鞋底、角色的脚弓如果直接把射线落点当Effector脚会陷进地面一个脚踝高度。正确做法是EffectorWorldLocation HitLocation HitNormal * FootHeightOffset;FootHeightOffset就是脚踝骨骼到脚底的距离一般取10-20厘米具体看角色模型可以在蓝图上做个可调参数慢慢试。另外建议射线打出来的落点要做水平方向的偏移修正因为脚踝正下方未必是脚掌着地的中心点如果角色的脚比较长前脚掌踩到了更低的台阶而脚踝正下方悬空那用正下方的落点会让整个脚掌“搭”在边缘上。常见的做法是打两条射线一条从脚踝一条从脚趾取两者中更高的落点取更高是因为脚掌必须支撑在地面上方取更低会导致穿模。2.2 脚掌旋转射线打到法线之后怎么转成脚骨头的旋转值先说射线。用Sphere Trace by Channel从脚踝位置往下发射Trace的起始点建议放在脚踝高度往上抬10-15厘米的地方终止点放到脚踝高度往下30-40厘米。用Sphere的好处是比LineTrace更稳定LineTrace在凹凸不平的地面上容易“戳进”石头缝隙产生很跳的法线值球体追踪相当于一个过滤器取的是接触面的平均趋势。射线打到的Result里最重要的数据是两个ImpactPoint落点和ImpactNormal法线。ImpactPoint用来做位置IKImpactNormal用来做角度旋转。我们的目标旋转是让脚掌骨骼的Z轴与地面法线对齐。但脚掌骨骼本身是有初始姿态的直接拿法线当旋转值肯定不对必须先拿到“脚掌骨骼自身在世界空间中的当前姿态”再计算一个delta rotation。做法如下拿脚踝骨骼的世界旋转WorldRotation。目标旋转 RInterpTo(当前旋转, 目标旋转, DeltaTime, 速度)目标旋转通过VectorRToQuaternion或者MakeRotFromZ来构造其中的Z轴向量就是射线法线。但直接MakeRotFromZ有一个问题——它只约束了Z轴朝上脚掌绕Z轴自转的角度是随机的会导致脚趾朝向忽左忽右看起来像崴脚。所以要改用MakeRotFromXZ或者限定Yaw角用手动计算的方式保留当前旋转的Yaw值只去调整Pitch和Roll。具体到蓝图节点我的做法是先分解当前旋转为(Yaw, Pitch, Roll)然后对法线做同样的分解拼接一个新的旋转Yaw保持当前角色的朝向不变Pitch和Roll用法线的角度。这类计算在动画蓝图里用独立函数封装调用不卡帧。还有一点非常重要角度插值的速度不能只用固定的插值速度要结合脚部的步态相位。脚在腾空阶段时旋转调整速度要快尽快匹配将要踩到的地面脚在着地支撑阶段时旋转调整速度要慢避免重心转移时脚掌乱转。这个需求用曲线驱动插值速度最方便在动画蓝图里引入一个FootRotationInterpSpeed曲线根据步态周期采样。2.3 骨盆重心的补偿脚部贴合后身体不能跟着塌下去当脚踝被IK钉到地面上而脚掌又旋转贴上了坡面角色的腿部曲线会变身体高度自然而然就会受影响。如果不做骨盆补偿角色在斜坡上会变成“跛脚”姿态——一条腿被拉长一条腿被压短。骨盆补偿的原理并不复杂在动画蓝图中获取两脚落地点的平均高度差当两只脚的Effector目标点高度不一致时就要把骨盆骨骼沿世界Z轴上下平移让两条腿的弯曲程度看起来更自然。具体操作用GetSocketTransform拿左右脚踝的世界位置相减得到高度差乘以系数后作为骨盆骨骼的Offset。系数取多少取决于腿长和骨盆宽度一般建议从0.3开始调系数太大角色会撅屁股。如果用的是UE4自带的CharacterMovementComponent还要同步调整胶囊体的Capsule Half Height避免角色脚部悬空后胶囊体却还保持原高度导致镜头位置和中弹判定诡异。Capsule的调整值就是骨盆偏移值在动画蓝图中设置好之后通过Character Movement的SetCapsuleHalfHeight接口在Tick中同步。注意调整胶囊体时要同时调整Mesh的Relative Location否则网格体模型会与胶囊体错位。3. 实操步骤从动画蓝图到脚下坡面的完整链路下面我把完整流程分步骤串一遍包含准备阶段、射线阶段、匹配阶段和权重控制阶段跟着做基本能跑通。我默认你已经有一个带腿部骨骼和动画蓝图的基础第三人称角色。3.1 准备工作骨骼命名、碰撞通道和动画曲线确认骨骼名称打开骨骼树查看脚踝骨骼始末端的命名常见的名称有foot_l、foot_r、ball_l、ball_r。动画蓝图中最后选IK Bone时用的就是这些骨骼名称命名不统一会白折腾半小时。碰撞预设射线追踪的Channel用Visibility或者WorldStatic就行。注意如果你用的角色蓝图里胶囊体、网格体自身也开启了Visibility通道那Trace会打到自己的脚上导致射线永远返回一个极近的点——这种问题非常隐蔽。建议单独建一个TraceResponseMap忽略自己。更稳妥的做法是射线通道自定义一个FootIKChannel只让地形Landscape和静态网格体响应。动画曲线如果角色用的是普通的Locomotion动画没有专门的步态曲线需要自己通过SBoneMask或者CurveValue判断脚是否着地。最简单的方法是取两根脚踝骨骼的世界速度速度小于阈值就认为是支撑相大于阈值就是摆动相。这个阈值需要根据动画实际速度测试一般是30-60单位/秒。3.2 射线检测两条射线和一个防抖动设计进入动画蓝图新建一个事件图表在Event Blueprint Update Animation中做以下操作取左右脚踝骨骼的世界位置分别记为LeftAnklePos、RightAnklePos。每个脚做一条射线起始点 脚踝位置 上抬15厘米终点 脚踝位置下压45厘米。射线类型选SphereRadius设为3-5厘米用球体追踪过滤细微凹凸。命中条件里要写忽略自身Collision通道见上一步。命中时记录ImpactPoint和ImpactNormal。这里说一下防抖动设计即使使用SphereTrace在凹凸明显的岩石地形上ImpactNormal还是会跳变。建议在蓝图里做一个“历史缓存”结构体每次命中后把法线存入缓存数组取最近N帧比如5帧的平均值作为最终法线。这个方法比单纯用插值更平滑尤其在角色大步跑动、脚踝速度较快时能明显减少脚掌旋转的震颤感。3.3 计算脚掌旋转保留Yaw只调Pitch和Roll这一步在动画蓝图里用自定义函数封装函数名可以叫CalculateFootRotation。输入参数是脚踝的世界旋转和射线法线输出是目标旋转。将当前脚踝旋转分解为CurrentYaw。对法线向量MakeRotFromZ再分解取它的Pitch和Roll。组合出目标旋转(CurrentYaw, NormalPitch, NormalRoll)。用RInterpTo进行旋转插值插值速度曲线化。这里AC玩家可能会问为什么不直接用MakeRotFromXZ把角色前向方向和法线作为两个轴因为角色的前向方向如果不翻转在斜坡上脚趾会被强行扭曲成面向坡面方向出现“顺拐”的观感。所以必须保留Yaw值。实测下来Yaw不动的效果在斜坡、楼梯上最自然。3.4 计算位置偏移为什么不直接用射线落点刚才提到过射线落点不能直接作为Two Bone IK的Effector要加上脚踝到脚底的高度偏移。但实际项目中这个偏移并非固定值——角色穿不同的鞋子、模型缩放、坡度的变化都会影响视觉结果。所以我的做法是做一个可配置参数组参数作用建议取值FootHeightOffset脚踝到脚底的高度补偿10-20cmPelvisOffsetCoef骨盆高度补偿强度0.3-0.5TraceUpDistance射线起点的上抬量10-15cmTraceDownDistance射线下行的最大距离40-60cm法线平滑帧数平均法线的历史帧数3-5帧把这些参数暴露到动画蓝图的Details面板调试时不用改代码直接调参。3.5 权重控制怎么让IK在跑步时不“爆炸”如果每帧都让Two Bone IK生效角色走路时会变成“吸盘脚”——脚一直像个磁铁一样被吸到地上走路、跑步的动态感全没了还会让膝盖弯曲角度变得非常奇怪。所以一定要用动态权重来控制IK强度。我的做法是用动画曲线的“GroundSpeed”来判断当角色速度小于某个阈值如100时权重缓慢提到1当速度超过阈值权重降到0.3-0.5如果角色在跳跃空中权重直接归零。这样做的结果是站立和慢走时IK效果最强脚部稳稳贴地跑步和冲刺时IK减弱保留动画本身的运动感同时脚部轻微跟随地面不会显得太飘。这个权重还可以叠加“当前脚是否支撑”的判断。用GetCurveValue获取Locomotion里的曲线比如FootL_Weight、FootR_Weight如果没有现成曲线就用脚踝速度阈值判断速度低于阈值说明脚在地面支撑IK权重拉满速度高于阈值说明脚在空中摆动IK权重降到最低。用速度阈值判断时注意加一点滞回区间比如阈值是60那么速度降至40才开始降权、升至80才开始升权防止权重在两帧之间来回跳。4. 常见问题与排查技巧实录做脚部IK的过程中我踩过不少坑很多问题是看着不大、排查起来折腾一整天。这里把典型的几个问题整理成速查表并附上排查思路。现象可能原因排查方向角色上坡时全身抖动射线检测的法线没有被平滑或者骨盆补偿系数过大检查法线平均/插值逻辑把PelvisOffsetCoef调小脚掌被“吸”在地面走不动IK权重一直为1摆动相时也在生效检查IK权重的步态判断逻辑确认摆动相权重是否已降低膝盖反折Joint Target Location未正确设置检查Joint Target目标点是否位于膝盖前方和上方台阶上脚掌仍然翘起来SphereTrace从脚踝正下方打台阶边缘探测不到增加一条脚趾方向的射线取更高落点法线旋转时脚趾乱甩MakeRotFromZ导致Yaw随机化改用保留Yaw只调Pitch/Roll的方案角色贴斜坡时胶囊体和网格体错位胶囊体高度调整与Mesh偏移不同步确保CapsuleHalfHeight调整后同步修改MeshRelativeLocation的Z值Trace总是打到角色自己Trace通道没忽略自身单独用FootIK通道忽略Pawn和自己的Collision上下坡瞬间脚快速“闪”到新角度插值速度过大几乎没有平滑降低RInterpTo速度和法线平均帧数逐步逼近楼梯上脚底一直悬空约1厘米FootHeightOffset设置过大逐个调节FootHeightOffset观察脚底和台阶面的缝隙除了这些还有一个非常关键但不容易察觉的配置UROUpdate Rate Optimization。UE4的骨骼网格体默认开启了Optimize Animation在距离过远或者模型较小时动画更新会降帧率导致IK的射线检测和骨骼解算结果在视觉上“卡”住了。如果你在PC上调试正常打包到主机/低端设备上发现斜坡IK有时不生效大概率就是这个。排查方式是把动画蓝图的Update Rate Optimization关掉或者把Mesh的Visibility Based Anim Tick Option改为Always Tick Pose。另外如果角色穿了铠甲、裙甲之类腿部IK会和这些半裙类骨骼通常挂在骨盆或大腿骨骼下面发生冲突——骨架里骨骼的Transform修改会自动影响子骨骼IK旋转大腿时裙甲也会跟着动。这类部件最好用完全独立的骨骼链通过Character Customization的方式组织或者零部件动画时把这些骨骼的IK权重设置为0。5. 后续扩展从双脚到四足从动画到外设聊完基础方案再说几招扩展做法有些是高级动画里常用的有些则是我自己实际项目中摸索出来的。5.1 四足生物四条腿怎么处理四足生物马、狼、机械狗和双足角色最大的区别在于四条腿的支撑相和摆动相是两两交替的IK权重控制要比双足复杂得多。但核心逻辑完全一样每条腿各自做射线检测、取法线、做Two Bone IK骨盆补偿根据前腿和后腿的平均高度分别处理。唯一容易出现的问题是前腿和后腿的射线法线不一致时躯干会被拧成麻花。解决办法是躯干骨骼不直接做旋转补偿而是基于四脚落点的平均值做个所有脚共同的平面拟合用这个平面的法线去旋转躯干。这个做法跑通之后四足动物的爬山效果非常好看——身体会随坡面自然俯仰四条腿各自踩在有效支撑点上上下楼梯也不再穿帮。5.2 和物理模拟器的配合其实是互补关系开头提到的“查询和物理模拟器的区别”在这里特别适合展开说。UE4里物理系统有两种工作方式一种是查询Query也就是射线检测、碰撞检测它只管“问”场景里的物体在哪儿、法线朝哪不涉及任何力和运动另一种是模拟器Simulation作用于有质量和大小的Actor或Constraint会施加力、产生加速度、影响运动轨迹。脚部IK用的是“查询”那一套因为我们只需要知道地面高度和法线值。而如果你想做“角色踩到震动物体时脚会被弹开”这种效果那就要让脚踝骨骼变成模拟约束的一部分让物理反馈影响脚掌位置——这时就不该用IK来钉脚了而是用AnimDynamics或者Physics Constraint去反向驱动。实际项目里把这两者结合的效果最棒用IK查询保证脚部贴合用物理模拟给脚部叠加“被扰动”的偏移。比如角色站在一辆颠簸的卡车上IK负责把脚钉到车厢地板而车厢地板的震动通过物理模拟叠加到脚掌上这样角色看起来既有“吸附地面”的稳又有“被震动影响”的自然晃动。5.3 外接设备映射用动捕或触觉设备辅助调参做脚部IK调试的时候最难的是判断“这个角度自然不自然”。纯靠肉眼和经验有时候一个坡度调一整天都调不好。我的做法是接外接设备映射用体感手柄比如PS Move、Kinect之类或者简单的旋转传感器映射到脚踝骨骼的旋转上直接手动控制脚掌角度实时观察角色的姿态变化。这个思路特别适合验证插值速度和平滑参数——你手动把设备快速旋转看角色脚掌跟得快不快、会不会震荡比反复改代码参数高效得多。我在一个项目中调试斜坡上30度到45度过渡区的脚掌旋转表现用映射设备把参数调完了整个过程只花了几分钟比纯靠看动画快了好几倍。另外如果你能拿到设备的Z轴旋转数据还可以顺带测试脚趾骨骼ball骨骼的弯曲——很多角色模型有脚趾关节斜坡角度太大时脚趾的弯曲会极大提升真实感。这块逻辑和脚掌旋转完全一样只是骨骼换成脚趾射线不做直接用脚掌法线做一个二次偏转。最后分享一个我的经验任何IK系统都需要在FPS视角下单脚测试。角色闲置站立、单脚踩在坡上、另一只脚悬空这是最容易暴露问题的状态。我几乎每次都是在闲置动画里发现脚部IK的边界情况——比如角色重心偏移时骨盆补偿会和脚部IK互相牵扯导致角色在坡上歪斜。调好这个状态跑动和上下坡的稳定性基本就稳了。脚部贴合这个课题看起来是个小功能但牵扯到动画系统、物理系统、角色组件配置甚至外设联动。动手做之前先理清楚“位置”“角度”“重心”三个维度各自的职责做的时候用曲线和参数化控制留足调节空间遇到问题时按表中列的排查思路逐项定位最终效果不会差。如果调试过程中遇到什么奇怪的现象欢迎随时交流我尽量把经验聊透。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门