FABRIK无需解角度,仅通过两次位置迭代即可收敛,适合UE5或自研引擎中的手部IK与机械臂末端定位,单次迭代开销极低,10关节链可在普通CPU上实时运行。

直接判断:FABRIK 不需要解角度,只操作位置,适合C++实时动画场景
如果你在UE5或自研引擎中做角色手部IK、机械臂末端定位,又不想碰四元数旋转、矩阵求逆或雅可比伪逆——FABRIK 是最轻量、最稳、最容易落地的选择。它不计算任何旋转,只靠两次位置拉扯(后往前 + 前往后)就收敛,单次迭代开销极低,10关节链在普通CPU上每帧
核心步骤:两次遍历 + 长度约束必须显式维护
关键不是“怎么写循环”,而是每一步都得保证:相邻关节距离严格等于原始骨骼长度。漏掉这个,链会缩/胀,动画立刻穿模。
-
chain_list必须是按父子顺序排列的指针/引用数组,chain_list[0]是根,chain_list[n-1]是末端 - 首次遍历(从末端往根):
end.global_location = target;然后对每个i从n-2到0,执行:chain_list[i].global_location = chain_list[i+1].global_location + (dir * chain_list[i].bone_length),其中dir是单位向量normalize(chain_list[i].global_location - chain_list[i+1].global_location) - 二次遍历(从根往末端):
chain_list[0].global_location必须锁死回原始位置(否则根会漂移);然后对每个i从1到n-1,执行:chain_list[i].global_location = chain_list[i-1].global_location + (dir * chain_list[i-1].bone_length),dir是normalize(chain_list[i].global_location - chain_list[i-1].global_location) - 重复上述两遍,直到
distance(chain_list[n-1].global_location, target) 或达到 <code>max_iterations
不可达目标的处理:别硬拉根,用伸直策略
当 target 距离根节点超过整条链总长时,强行把根往目标方向挪会导致姿态崩坏(比如角色肩膀被拽出胸腔)。标准做法是:
- 先算总长
total_length = sum(bone_length for each bone) - 再算
root_to_target = length(target - chain_list[0].global_location) - 若
root_to_target > total_length,则不做迭代,直接将整条链拉成直线:从根开始,每个关节沿normalize(target - chain_list[0].global_location)方向,按顺序放置,间距为各自bone_length - 该策略在UE的
FABRIK IK节点里默认启用,C++实现时漏掉这步,角色伸手够不到物体会突然“炸开”
容易踩的坑:浮点误差累积、根节点未锁定、骨骼长度非恒定
这三个问题占FABRIK实操失败的90%以上。
立即学习“C++免费学习笔记(深入)”;
- 每次计算
dir前必须normalize(),且要防零向量:if (length_sq ,否则除零或NaN会污染后续所有位置 -
chain_list[0].global_location在二次遍历开头必须强制赋值回原始位置(不是“保持不动”,是“明确设回”),否则一次迭代后根就开始漂移 -
bone_length必须是初始化时缓存的标量,不能每次从当前两关节位置动态算——因为位置已在迭代中变动,再算就失去约束意义 - 如果骨骼带缩放(比如FBX导入时有非均匀缩放),
bone_length要提前乘以局部缩放因子,否则链会变短/变长
真正难的不是算法本身,是把位置约束和坐标系一致性守住。一旦某根骨骼的 global_location 混了局部/世界空间,或某次 normalize 没判零,整个链就会在几帧内发散。建议在调试时打印前3次迭代的末端误差和各段实际长度,比看最终结果更快定位问题。


















